Quick review of OAuth 2
OAuth 2 is a protocol for authorization provider.
Authorization provider means it grants access control for resources (RestFul APIs for example).
OAuth 2 Provider is consisted with 2 components. Authorization Server and Resource Server. Resource Server can be local or remote.
The resources within the Resource Server are protected by scopes. Scopes is like the catalogs within a supermarket. When you obtain an access_token, it bears the scopes that are granted. You can use your access_token for only those granted scopes and also within the expiry times. You have option to use refresh_token to renew the access_token. The refresh_token is optionally issued together with access_token.
Client Application as the holder of access_token. Client Application doesn't have to manage the Resource Owner's credential, but still have safe way to access resources on behalf of the Resource Owner. The following diagram depicts the relationship between each roles.
The typical flow will be:
- User tries to use Client Application, and Client Application needs to access some personal information from Resource Server to achieve personalized user experience.
- The Client Application then send request to Authorization Server to obtain an access_token in order to access resources on behalf of Resource Owner.
- The Authorization Server then challenges the user's credential and also optionally ask for user to grant for the scopes required to the Client Application, at the end the Client Application obtains the access_token.
- Then Client Application uses the access_token to access the protected resources on behalf of Resource Owner.
How to request an access_token from Authorization Server?
The REST-like authorization endpoint is for requesting access_token, but it could be two steps of getting access_token. When the authorization endpoint triggers two steps flow, the token endpoint is for finally getting the access_token.
Authorization endpoint
This is always the start point for whoever needs to acquire an access_token. Depends on the parameters sent with the endpoint, if it is two steps flow, then the following request to token endpoint will be necessary.
URL: /authorize. It depends on implementation.
Required Parameters:
- response_type: It can be "code" or "token", or registered extension value. "code" will triggers a two-steps flow to obtain access_token. "token" means to return access_token in one step.
- redirect_uri: the Client Application's absolute uri after authorization flow is finished, the user agent will be used to redirect to.
Token endpoint
The token endpoint is used by the client to obtain an access token by presenting its authorization grant or refresh token.
URL: /token. It depends on implementation.
Required Parameters:
- grant_type: It tells how the Authorization Server should trust the request in order to issue access_token.
- refresh_token: If the grant_type is refereh_token, then you need to provide refresh token.
- redirect_uri: This has to be identical with the one sent from authorization endpoint.
What OAuth 2 provider is not?
OAuth 2 Provider is not authenticating user for the Client Application (only authenticate user for its own). Client Application has to use its own machoism to authenticate user if needed and manage the authenticated session. Resource Owner can be anonymous to the Client Application. For example, the Client Application has only age requirement, so instead to ask user to provide age, the Client Application can request user to grant access to Facebook to verify the age from the Facebook, then user can freely use application. This Application doesn't require identify from user and no need for an authenticated session either.
Reference reading: An introduction to OAuth2
OpenId Connect is an Authentication Layer on top of OAuth 2 for Client Applications
OpenID Connect is a simple identity layer on top of the OAuth 2.0 protocol, which allows computing clients to verify the identity of an end-user based on the authentication performed by an authorization server, as well as to obtain basic profile information about the end-user in an interoperable and REST-like manner.
- OIDC uses OAuth 2 extension to define a scope called "openid".
- OIDC defines an extension for response_type called "id_token" in addition to default "code" and "token".
- The ID Token is a security token that contains Claims about the Authentication of an End-User by an Authorization Server when using a Client. ID Token can potentially contains other requested Claims as well. ID Token is usually returned together with access_token from Authorization Server.
- OIDC defines another endpoint "user_info" endpoint, this endpoint is protected by "openid" scope. This is the endpoint on OIDC Provider to return Claims of End-User.
Response type in Authorization endpoint
Response_type indicates what will be returned from authorization endpoint. There're 3 options: "code", "token", and "id_token" with any combination.
- Code. This triggers two steps flow to obtain access_token. Code first, then use code to exchange token from token endpoint.
- Token.
- So total combinations will be 3 + 3 + 1 = 7.
- You want to use OIDC for either authorization only or authorization and authentication.
- For authorization only, your goal is to get an access_token.
- For authentication only, you goal is to get an id_token.
- For authorization and authentication, your goal is to get access_token and id_token.
- Based on what goal you want to achieve and what response_type you are requesting, it will end up different process flow. Mainly:
- If the response_type is "code" only, it will trigger "authorization code" flow.
- If the response_type has no "code", it will trigger "implicit" flow.
- If the response_type has "code" and anything else as combination, it will trigger "hybrid" flow.
- For authorization only, your goal is to get an access_token.
- For authentication only, you goal is to get an id_token.
- For authorization and authentication, your goal is to get access_token and id_token.
- If the response_type is "code" only, it will trigger "authorization code" flow.
- If the response_type has no "code", it will trigger "implicit" flow.
- If the response_type has "code" and anything else as combination, it will trigger "hybrid" flow.
Grant Types in Token endpoint
The OAuth 2 specification describes five grants for acquiring an access token:
Grant type Description
Request Parameters
(To token endpoint)
Response Values
Link to Specification
Authorization code grant
This is used in authorization code flow. A back channel /token endpoint request.
NOTE: to authorization endpoint
response_type=
code
client_id=lient identifier>
redirect_uri
with the client redirect URI. This parameter is optional, but if not send the user will be redirected to a pre-registered redirect URI.
scope
a space delimited list of scopes
state
with a CSRF token. This parameter is optional but highly recommended. You should store the value of the CSRF token in the user’s session to be validated when they return.
code
with the authorization code
state
with the state parameter sent in the original request. You should compare this value with the value stored in the user’s session to ensure the authorization code obtained is in response to requests made by this client rather than another client application.
Then to token endpoint
grant_type=authorization_
code. The code from previous step
client_id=<
client identifier>
- client_secret=
token_type
with the value Bearer
expires_in
with an integer representing the TTL of the access token
access_token
the access token itself
refresh_token
a refresh token that can be used to acquire a new access token when the original expires
Implicit grant This is used in implicit flow. There's no token end point is allowed to access.
NOTE: to authorization endpoint
response_type
with the value token
client_id
with the client identifier
redirect_uri
with the client redirect URI. This parameter is optional, but if not sent the user will be redirected to a pre-registered redirect URI.
scope
a space delimited list of scopes
state
with a CSRF token. This parameter is optional but highly recommended. You should store the value of the CSRF token in the user’s session to be validated when they return.
token_type
with the value Bearer
expires_in
with an integer representing the TTL of the access token
access_token
the access token itself
state
with the state parameter sent in the original request. You should compare this value with the value stored in the user’s session to ensure the authorization code obtained is in response to requests made by this client rather than another client application.
Resource owner credentials grant
This grant is a great user experience for trusted first party clients both on the web and in native device applications.
grant_type
with the value password
client_id
with the the client’s ID
client_secret
with the client’s secret
scope
with a space-delimited list of requested scope permissions.
username
with the user’s username
password
with the user’s password
token_type
with the value Bearer
expires_in
with an integer representing the TTL of the access token
access_token
the access token itself
refresh_token
a refresh token that can be used to acquire a new access token when the original expires
Client credentials grant
The simplest of all of the OAuth 2.0 grants, this grant is suitable for machine-to-machine authentication where a specific user’s permission to access data is not required.
grant_type
with the value client_credentials
client_id
with the the client’s ID
client_secret
with the client’s secret
scope
with a space-delimited list of requested scope permissions.
token_type
with the value Bearer
expires_in
with an integer representing the TTL of the access token
access_token
the access token itself
Refresh token grant This grant is used to refresh the access_token with refresh_token
grant_type
with the value refresh_token
refresh_token
with the refresh token
client_id
with the the client’s ID
client_secret
with the client’s secret
scope
with a space-delimited list of requested scope permissions. This is optional; if not sent the original scopes will be used, otherwise you can request a reduced set of scopes.
token_type
with the value Bearer
expires_in
with an integer representing the TTL of the access token
access_token
the access token itself
refresh_token
a refresh token that can be used to acquire a new access token when the original expires
Grant type | Description |
Request Parameters
(To token endpoint)
| Response Values |
Link to Specification
|
---|---|---|---|---|
Authorization code grant |
This is used in authorization code flow. A back channel /token endpoint request.
| NOTE: to authorization endpoint
|
|
|
Then to token endpoint
|
| |||
Implicit grant | This is used in implicit flow. There's no token end point is allowed to access. | NOTE: to authorization endpoint
|
| |
Resource owner credentials grant
| This grant is a great user experience for trusted first party clients both on the web and in native device applications. |
|
| |
Client credentials grant
| The simplest of all of the OAuth 2.0 grants, this grant is suitable for machine-to-machine authentication where a specific user’s permission to access data is not required. |
|
| |
Refresh token grant | This grant is used to refresh the access_token with refresh_token |
|
|
3 Authentication Flows
Different response_type presented within authorization endpoint determines different authentication flow.
Comparison of 3 different Authentication Flow
Authentication Flow
response_type
grant_type
Description
Typical Scenario
Authorization Code Flow
- code
- authorization_code
- All tokens returned from Token Endpoint
- Tokens not revealed to User Agent
Web application with backend support.
Implicit Flow
- id_token
- id_token token
- implicit
- implicit
- All tokens returned from Authorization Endpoint
- Client can not be authenticated
- Refresh Token is not possible
- Communication in one round trip
- Implicit grant type is actually there's no access token request
Native mobile application. It doesn't require user authentication, and also it doesn't need to refresh the access token.
Hybrid Flow
- code id_token
- code token
- code id_token token
- authorization_code, implicit
- authorization_code, implicit
- authorization_code, implicit
Authentication Flow
|
response_type
|
grant_type
|
Description
|
Typical Scenario
|
---|---|---|---|---|
Authorization Code Flow |
|
|
| Web application with backend support. |
Implicit Flow |
|
|
| Native mobile application. It doesn't require user authentication, and also it doesn't need to refresh the access token. |
Hybrid Flow |
|
|
Authorization Code Flow
Implicit Flow
(As reference only, it can be very different based on different combination of response_type)
Hybrid Flow
(As reference only, it can be very different based on different combination of response_type)
ID Token
The ID token resembles the concept of an identity card, in a standard JWT format, signed by the OpenID Provider (OP). To obtain one the client needs to send the user to their OP with an authentication request.
Features of the ID token:
- Asserts the identity of the user, called subject in OpenID (sub).
- Specifies the issuing authority (iss).
- Is generated for a particular audience, i.e. client (aud).
- May contain a nonce (nonce).
- May specify when (auth_time) and how, in terms of strength (acr), the user was authenticated.
- Has an issue (iat) and an expiration date (exp).
- May include additional requested details about the subject, such as name and email address.
- Is digitally signed, so it can be verified by the intended recipients.
- May optionally be encrypted for confidentiality.
The ID token statements, or claims, are packaged in a simple JSON object:
The ID token header, claims JSON and signature are encoded into a base 64 URL-safe string, for easy passing arround, for example as URL parameter.
You can read more about the JWT data structure and encoding in RFC 7519.
You can read more about the JWT data structure and encoding in RFC 7519.
JWT (JSON Web Token)
For example:
With JWT
eyJraWQiOiJyc2ExIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJlNWI2NTIzZC02OWVmLTQ0NjItYmYxOC1mZTUwNDg1ZTJiMTAiLCJhdWQiOiIxMTE3NTkyMi1hNmI5LTRmMGQtOGY3Zi1mNzg3ZGM2ZGJmNDkiLCJhdXRoX3RpbWUiOjE0ODM4OTYyMzEsImtpZCI6InJzYTEiLCJpc3MiOiJodHRwczpcL1wvd3d3Lm1hcGxlLmNvbVwvb2lkYyIsImV4cCI6MTQ4Mzg5NzY2NywiaWF0IjoxNDgzODk3MDY3LCJub25jZSI6IjExZmU2NWZiZDM1YmIiLCJqdGkiOiJmN2M4NzZhNC0yZmQzLTQwMWEtODc4Ni01MGEyYWQwZjU5MjEifQ.RL_48lqbsAzJfaRK5y-sE-CAcMS5x1nIegI-rIbEg2fcUTpV-jprxLDBcKclBB-uz7XdblNtOMLYz4UKUwregxV16sMaYKB0QOMpbt7VXi-Tlarg7lQZMuwCnh3-pDR7i2Bd1mChkB02NHzB3GZxNYj7z1jQG5upiHAqGGiqOaw
This represents:
Part 1 Header eyJraWQiOiJyc2ExIiwiYWxnIjoiUlMyNTYifQ
{
"kid": "rsa1",
"alg": "RS256"
}
Part 2 Payload
eyJzdWIiOiJlNWI2NTIzZC02OWVmLTQ0NjItYmYxOC1mZTUwNDg
1ZTJiMTAiLCJhdWQiOiIxMTE3NTkyMi1hNmI5LTRmMGQtOGY3Zi
1mNzg3ZGM2ZGJmNDkiLCJhdXRoX3RpbWUiOjE0ODM4OTYyM
zEsImtpZCI6InJzYTEiLCJpc3MiOiJodHRwczpcL1wvd3d3Lm1hcG
xlLmNvbVwvb2lkYyIsImV4cCI6MTQ4Mzg5NzY2NywiaWF0IjoxND
gzODk3MDY3LCJub25jZSI6IjExZmU2NWZiZDM1YmIiLCJqdGkiO
iJmN2M4NzZhNC0yZmQzLTQwMWEtODc4Ni01MGEyYWQwZjU5
MjEifQ
{
"sub": "e5b6523d-69ef-4462-bf18-fe50485e2b10",
"aud": "11175922-a6b9-4f0d-8f7f-f787dc6dbf49",
"auth_time": 1483896231,
"kid": "rsa1",
"iss": "https://www.maple.com/oidc",
"exp": 1483897667,
"iat": 1483897067,
"nonce": "11fe65fbd35bb",
"jti": "f7c876a4-2fd3-401a-8786-50a2ad0f5921"
}
Part 3 Signature RL_48lqbsAzJfaRK5y-sE-CAcMS5x1nIegI-rIbEg2fcUTpV-jprxLDBcKclBB-uz7XdblNtOMLYz4UKUwregxV16sMaYKB0QOMpbt7VXi-Tlarg7lQZMuwCnh3-pDR7i2Bd1mChkB02NHzB3GZxNYj7z1jQG5upiHAqGGiqOaw HMACSHA256(base64enc(header) + '.' + base64enc(payload), secretKey)
Part 1 | Header | eyJraWQiOiJyc2ExIiwiYWxnIjoiUlMyNTYifQ |
{
"kid": "rsa1",
"alg": "RS256"
} |
Part 2 | Payload |
eyJzdWIiOiJlNWI2NTIzZC02OWVmLTQ0NjItYmYxOC1mZTUwNDg
1ZTJiMTAiLCJhdWQiOiIxMTE3NTkyMi1hNmI5LTRmMGQtOGY3Zi
1mNzg3ZGM2ZGJmNDkiLCJhdXRoX3RpbWUiOjE0ODM4OTYyM
zEsImtpZCI6InJzYTEiLCJpc3MiOiJodHRwczpcL1wvd3d3Lm1hcG
xlLmNvbVwvb2lkYyIsImV4cCI6MTQ4Mzg5NzY2NywiaWF0IjoxND
gzODk3MDY3LCJub25jZSI6IjExZmU2NWZiZDM1YmIiLCJqdGkiO
iJmN2M4NzZhNC0yZmQzLTQwMWEtODc4Ni01MGEyYWQwZjU5
MjEifQ
|
{
"sub": "e5b6523d-69ef-4462-bf18-fe50485e2b10",
"aud": "11175922-a6b9-4f0d-8f7f-f787dc6dbf49",
"auth_time": 1483896231,
"kid": "rsa1",
"iss": "https://www.maple.com/oidc",
"exp": 1483897667,
"iat": 1483897067,
"nonce": "11fe65fbd35bb",
"jti": "f7c876a4-2fd3-401a-8786-50a2ad0f5921"
} |
Part 3 | Signature | RL_48lqbsAzJfaRK5y-sE-CAcMS5x1nIegI-rIbEg2fcUTpV-jprxLDBcKclBB-uz7XdblNtOMLYz4UKUwregxV16sMaYKB0QOMpbt7VXi-Tlarg7lQZMuwCnh3-pDR7i2Bd1mChkB02NHzB3GZxNYj7z1jQG5upiHAqGGiqOaw | HMACSHA256(base64enc(header) + '.' + base64enc(payload), secretKey) |
Claims
Claims is the information about a user.
There are 3 types of claims
-
Normal claims.
-
Aggregated claims.
-
Distributed claims.
Normal claims.
Aggregated claims.
Distributed claims.
There are 2 ways to retrieve claims
- Request Claims from Scope. The each scope can have claims associated with.
- Request claims with claims "request parameter" or "claim parameter" in the authorization endpoint.
There are 2 ways of returning the claims
- Returning claims within ID_token. When a response_type value is used that results in an Access Token being issued. However, when no Access Token is issued (which is the case for the response_type value id_token), the resulting Claims are returned in the ID Token.
- Returning claims within UserInfo endpoint. When no access_token is being issued, the claims will be returned from UserInfo endpoint.
Claim parameter in Authorization endpoint
OpenID Connect defines the following Authorization Request parameter to enable requesting individual Claims and specifying parameters that apply to the requested Claims:
claims OPTIONAL. This parameter is used to request that specific Claims be returned. The value is a JSON object listing the requested Claims.
The claims parameter value is represented in an OAuth 2.0 request as UTF-8 encoded JSON (which ends up being form-urlencoded when passed as an OAuth parameter). When used in a Request Object value, the JSON is used as the value of the claims member.
A claim request example:
The follow 2 requests should result the same, either use scope or use claims to request individual claims.
-
Use claim request.
Decoded claims request is like below
-
Use scope to request claims.
claims OPTIONAL. This parameter is used to request that specific Claims be returned. The value is a JSON object listing the requested Claims.
Use claim request.
Decoded claims request is like below
Use scope to request claims.
Request parameter in Authorization endpoint
OpenID Connect defines the following Authorization Request parameters to enable Authentication Requests to be signed and optionally encrypted:
request OPTIONAL. This parameter enables OpenID Connect requests to be passed in a single, self-contained parameter and to be optionally signed and/or encrypted. The parameter value is a Request Object value, as specified in Section 6.1. It represents the request as a JWT whose Claims are the request parameters.
request_uri OPTIONAL. This parameter enables OpenID Connect requests to be passed by reference, rather than by value. The request_uri value is a URL using the https scheme referencing a resource containing a Request Object value, which is a JWT containing the request parameters.
Requests using these parameters are represented as JWTs, which are respectively passed by value or by reference. The ability to pass requests by reference is particularly useful for large requests. If one of these parameters is used, the other MUST NOT be used in the same request.
Example of "request" parameter
Example of authorize request with "request" parameter:
request OPTIONAL. This parameter enables OpenID Connect requests to be passed in a single, self-contained parameter and to be optionally signed and/or encrypted. The parameter value is a Request Object value, as specified in Section 6.1. It represents the request as a JWT whose Claims are the request parameters.
request_uri OPTIONAL. This parameter enables OpenID Connect requests to be passed by reference, rather than by value. The request_uri value is a URL using the https scheme referencing a resource containing a Request Object value, which is a JWT containing the request parameters.
No comments:
Post a Comment