Skip to content

Added Guide chapter on Identity, Permissions and Scopes #17

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/guide/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Getting Started
---------------
* [What do you need to know before installing the Yii2-Oauth2-Server](start-prerequisites.md)
* [Installing the Yii2-Oauth2-Server](start-installation.md)
* [Identity, Permissions and Scopes](start-identity-permissions-and-scopes.md)
* [OpenID Connect for the Yii2-Oauth2-Server](start-openid-connect.md)
* [OpenID Connect Claims](start-openid-connect-claims.md)
* [Advanced Redirect URI Configuration](start-redirect-uris.md)
Expand Down
201 changes: 201 additions & 0 deletions docs/guide/start-identity-permissions-and-scopes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
Identity, RBAC Permissions and Scopes
=====================================

This chapter describes how the Yii2-Oauth2-Server integrates with the Yii2 user component, [RBAC permissions](
https://www.yiiframework.com/doc/guide/2.0/en/security-authorization#rbac) and the usage of OAuth 2.0 scopes.

OAuth 2.0 flows (3-legged vs 2-legged)
--------------------------------------
The OAuth 2.0 specification defines different authorization flows, called "grant types", which sometimes are grouped in
two types: "3-legged" and "vs "2-legged". The "legs" refer to the number of parties involved.

A typical OAuth2 flow involves three parties:
- the Resource Owner (often the end-user).
- the Client (often a web application or third-party application).
- and the Authorization and/or Resource server(s) (often the same server but can be different servers).
These roles are handled by the Yii2-Oauth2-Server

The grant types that follow this 3-legged flow are:
- Authorization Code Grant (recommended)
- Implicit Grant (legacy type, usage is discouraged)
- Password Credentials Grant (legacy type, usage is discouraged)

OAuth 2.0 can also be used without an end-user being involved, typically server-to-server, where the client is acting on
its own behalf (in this case the client is also the resource owner).

Currently, the Oauth 2.0 specification only defines one grant type for the 2-legged flow:
- Client Credentials Grant

### 3-legged OAuth 2.0 flow

The recommended grant type for 3-legged authentication is the Authorization Code Grant with PKCE enabled.

Authorization Code Flow:
```
+----------+
| Resource |
| Owner |
| |
+----------+
^
|
(2)
+----|-----+ Client Identifier +---------------+
| -+----(1)-- & Redirection URI ---->| |
| User- | | Authorization |
| Agent -+----(2)-- User authenticates --->| Server |
| | | (Yii2-Oauth2- |
| -+----(3)-- Authorization Code ---<| Server) |
+-|----|---+ +---------------+
| | ^ v
(1) (3) | |
| | | |
^ v | |
+---------+ | |
| |>---(4)-- Authorization Code ---------' |
| Client | & Redirection URI |
| | |
| |<---(5)----- Access Token -------------------'
+---------+ (w/ Optional Refresh Token)

Note: The lines illustrating steps (1), (2), and (3) are broken into two parts as they pass through the user-agent
(often the web browser).
```
1. The Client initiates the flow by directing the Resource Owner's user-agent to the authorization endpoint
(in this case the Yii2-Oauth2-Server).
The Client includes its client identifier, requested scope, local state, and a redirection URI to which the
Authorization Server (Yii2-Oauth2-Server) will send the user-agent back once access is granted (or denied).

2. The Authorization Server (Yii2-Oauth2-Server) authenticates the Resource Owner (end user) via the user-agent
and establishes whether the Resource Owner grants or denies the Client's access request.

3. Assuming the Resource Owner grants access, the Authorization Server (Yii2-Oauth2-Server) redirects the user-agent
back to the Client using the redirection URI provided earlier (in the request or during client registration).
The redirection URI includes an authorization code and any local state provided by the Client earlier.

4. The Client requests an access token from the Authorization Server's (Yii2-Oauth2-Server) token endpoint by
including the authorization code received in the previous step. When making the request, the Client authenticates
with the Authorization Server (Yii2-Oauth2-Server). The Client includes the redirection URI used to obtain the
authorization code for verification.

5. The Authorization Server (Yii2-Oauth2-Server) authenticates the Client, validates the authorization code, and ensures
that the redirection URI received matches the URI used to redirect the Client in step (3).
If valid, the Authorization Server (Yii2-Oauth2-Server) responds back with an access token and, optionally, a
refresh token.

### 2-legged OAuth 2.0 flow

The Client credentials Grant is used typically when the client is acting on its own behalf (server-to-server).

Client credentials flow:
```
+---------+ +---------------+
| | | |
| |>--(1)- Client Authentication --->| Authorization |
| Client | | Server |
| |<--(2)---- Access Token ---------<| (Yii2-Oauth2- |
| | | Server) |
+---------+ +---------------+
```

1. The Client authenticates (via its 'identifier' and 'secret') with the Authorization Server (Yii2-Oauth2-Server) and
requests an access token from the token endpoint.

2. The Authorization Server (Yii2-Oauth2-Server) authenticates the Client, and if valid, issues an access token.

Since the client authentication is used as the authorization grant, no additional authorization request is needed.


Yii2-Oauth2-Server Integration
------------------------------

The Yii2-Oauth2-Server integrates with the Yii2 application by taking care of the entire Oauth 2.0 flow.
After successful authorization, when the Client makes server requests with a valid authorization header
the Yii2-Oauth2-Server will set the Yii2 "user identity class" (`Yii::$app->user->identity`) for the "user component"
(`Yii::$app->user`).

### Identity and RBAC usage

Let's say that in our example there is a backend application (from now on abbreviated as BEA) has 2 roles:
'user' and 'admin'.
When a User authorizes a Client, let's say a frontend application(from now on abbreviated as BEA), to use the BEA,
all calls that are made by that Client will be automatically (under the condition that the Client correctly sends the
"authentication" header) done with that user's identity.

Let's say that whe have two users: Alice is "admin" and user Bob is a regular "user".

When Alice authorizes the FEA via the Authorization Code Grand the FEA can use the "bearer token" authorization header
to make API calls against the BEA. For all these calls the `Yii::$app->user->identity` will be set to the user identity
of Alice. When Bob would authorize the FEA all calls with his bearer token by the FEA will set the
`Yii::$app->user->identity` to Bob's identity.

Since the identity is set, you can simply use `Yii::$app->user->can('role_you_want_to_check')` anywhere you want.
E.g. `Yii::$app->user->can('admin')` would return `true` for Alice and `false` for Bob.

> Note: Until now "scope" is never used and probably is not needed.
Only when we have multiple clients, let's say FEA1 and FEA2, that need a different access scope for the *same* user,
scopes come into play.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is incorrect. As far as I know scopes are attached to access token and not clients.

Scopes are used from very beginning in OAuth 2.

I have used multiple access token with different scopes for same clients.

Example:

My app uses GitHub for login. OAuth 2 login. In addition to email+password. In that my app only request these scopes: read email + read basic profile info. If I login with GitHub I get access token which can only read user email and other basic profile info. With this token I cannot read user's private repo.

After login (by GitHub or email+password) my same app has this functionality: attach GitHub repo

My app allows users to host their project located in GitHub

When My app request GitHub to access repo I also add read_repo scope to the request. This time I get access token which allow me to read repo

So I have total 2 access token with different scopes.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, thanks for your extensive input.

The scope in the access token depends on the requested scope during the token request. The granting of scope however, is connected to the Client (for the specific user).
https://oauth.net/2/scope/ and https://www.oauth.com/oauth2-servers/scope/defining-scopes/

Does that resolve the concern you raised or did I miss something?


### Scope usage

> Scopes only come into play in delegation scenarios, and always *limit* what a Client can do on *behalf* of a user:
a scope cannot allow an application to do more than what the user can do.

Let's say (continuing from our sample above) that Bob (with the "user" role) wants to authorize two different clients:
- Your own front-end application (FEA) to read, create and delete emails on his behalf.
- A third-party app (from now on abbreviated as 3rdPA) to only create emails on his behalf.

In that case you would need to define the scopes 'read_email', 'create_email' and 'delete_email' and assign them to the
different Clients. Then Bob can specify which scopes the Client may use on his behalf during the authorization of the
Client.

Note that another user, let's say Charles (who also has the role "user"), can allow different scopes for the same
clients, e.g.:
- FEA1 may read and create emails on his behalf.
- 3rdPA may create and also delete emails on his behalf.

When scopes are used you can use `Yii::$app->getModule('oauth2')->requestHasScope('scope_you_want_to_check')` to see if
the client that makes the request has the required scope.

So in the case of Bob and Charles:
- `Yii::$app->user->can('admin')` would be `false` for both.
- `Yii::$app->user->can('user')` would be `true` for both.
- And when checking the scopes (`Yii::$app->getModule('oauth2')->requestHasScope('scope_you_want_to_check')`)
would yield the following (B = Bob, C = Charles):
| | 'read_email' | 'create_email' | 'delete_email' |
|--------|:--------------------:|:------------------:|:-------------------:|
| FEA1 | B:`true`, C:`true` | B:`true`, C:`true` | B:`true`, C:`false` |
| 3rdPA | B:`false`, C:`false` | B:`true`, C:`true` | B:`false`, C:`true` |

To summarize:
- Roles define what the User may do.
- Scopes *limit* what a Client may do on *behalf* of the User.
- If you don't need to limit what a Client may do on behalf of a User, you probably don't need scopes.
- If you do need scopes, you most likely need to check both the user Role and Scope. E.g.
```php
class EmailController extends Controller
{
public function actionCreate()
{
if (
!Yii::$app->user->can('user')
|| !Yii::$app->getModule('oauth2')->requestHasScope('create_email')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

           `|| !Yii::$app->getModule('oauth2')->requestHasScope('create_email')`

&& !Yii::$app->getModule('oauth2')->requestHasScope('create_email')

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think RBAC authorization and scopes based authorisation are different. We have to apply both

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is true.

Copy link
Owner Author

@rhertogh rhertogh Oct 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SOHELAHMED7 @mtangoo
If I'm not mistaken they are now required both because of the !, in other words:
If the user does not has the role 'user' or the request does not has the scope 'create_email' then throw the unauthorized exception.

) {
throw new UnauthorizedHttpException();
}
// ...
```

### Identity for 2-legged flow

When using 2-legged flow (Client Credentials Grant) for server-to-server communication there is no end-user involved.
In order to leverage the Yii2 identity and RBAC system you can assign a User identity to the Client.
This can be done via the `Oauth2ClientInterface::setClientCredentialsGrantUserId()` or in the database in the
`public.oauth2_client`.`client_credentials_grant_user_id` field.

It's recommended to create a dedicated User for the client and assign the required role(s) and/or permission(s)
to that User.

When configured, requests from Client using the Client Credentials Grant will have the User identity set to the
specified user. This way you can easily use the Yii2 RBAC system
(`Yii::$app->user->can('other_server_role_or_permission')`).
9 changes: 9 additions & 0 deletions docs/guide/start-installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,15 @@ It will list the current Oauth2Module settings and the server endpoints (along w

If everything is set up correctly your application now supports Oauth 2.0 🥳

Usage
-----
Since the Yii2-Oauth2-Server integrates with the Yii2 authentication system you can continue to use the user
component (`Yii::$app->user`) and identity (`Yii::$app->user->identity`).
For example (assuming you've set up [RBAC](https://www.yiiframework.com/doc/guide/2.0/en/security-authorization#rbac))
`Yii::$app->user->can('role_you_want_to_check')`.

For further details, please see [Identity, Permissions and Scopes](start-identity-permissions-and-scopes.md)

OpenID Connect
--------------
Please see [OpenID Connect for the Yii2-Oauth2-Server](start-openid-connect.md)
Expand Down