Authentication and Authorization
Web applications may contain both public and private data. Private data may be further restricted to only certain authorized users. Therefore the web application must first authenticate a user, and then determine what private data they are authorized to access. The OAuth 2.0 specification implements an alternative workflow which alows users to authorize another web application to access resources on their behalf. The specification states that OAuth 2.0 is not an authentication protocol. However, OpenID Connect does use OAuth 2.0 to implement a standard for authentication. GitHub is an example of the OpenID Connect standard, see Basics of Authentication.
The following definitions are from from the linked reference by Alex Bilbie.
- Resource (API) server: The server hosting the protected resources, capable of accepting and responding to protected resource requests using access tokens.
- Authorization server: The server issuing access tokens to the client after successfully authenticating the resource owner and obtaining authorization.
- Resource owner (the User): An entity capable of granting access to a protected resource. When the resource owner is a person, it is referred to as an end-user.
- Client: An application making protected resource requests on behalf of the resource owner and with its authorization. The term client does not imply any particular implementation characteristics (e.g. whether the application executes on a server, a desktop, or other devices).
Authorizing Users & Clients
There are four workflows supported by OAuth 2.0 that allow users to authorize
an application to obtain a
Bearer token to gain access to resources in lieu
of user credentials or client tokens.
- Authorization Code
- Resource Owner Password Credentials
- Client Credentials
- Implicit (not covered in this post)
This is the most secure workflow and is the preferred workflow for applications running on remote web servers that can store credentials confidentially. The process is documented in the OAuth 2.0 specification and in the References. The authorization code workflow consists of the following steps:
- Ask an administrator to create a client application with the desired grant
type. You should be given a
Then a registered client can send a
GETrequest to the authorization URL to redirect users to login with the identity provider and get an authorization code which can be exchanged by the client for an access token. For this example, we'll use the following fictitious authorization URL:
The authorization URL is very picky. It must include a the following query string parameters:
"client_id": <client-id>, "state": <optional>, "response_type": "code", "redirect_uri": <redirect_uri>, "scope": "read write email name"
The authorization can also include the desired scopes including any additional claims about the user such as:
openid, etc. that can be retrieved in the ID token from the
- Optionally, the authorization request should also contain a unique
statecode, a string of any length, used to prevent cross site forgery request. It's up to the client to save the state sent in the request and validate it with the state returned in the response from the authorization server.
- Optionally there may be an
approval_promptparameter that can be provided and set to either
auto. If not set, and there is a "skip authorization" checkbox in the app registration form which is disabled, then the default may be
forcewhich may ask users to authenticate everytime. To only ask users to authenticate the first time, try
- The identity provider will ask the user for their credentials if not already cached in the user's browser.
- Depending on the
approval_promptparameter or the "skip authorization" checkbox, the user may be prompted to authorize the token, with a list of the claims and scopes that the token is requesting.
- The authorization service returns a code and the state submitted by the client. The code can then be exchanged for an access token.
The redirect URI on the client side has 10 minutes, and one attempt to exchange the authorization code for an access token. This request is sent as a
The token URL is very picky. It must include the client's id and secret either as a basic authentication header or as payload data. Additionally the following data must also be in the payload of the
"grant_type": "authorization_code", "code": <code>, "redirect_uri": <redirect_uri>
The response is a JSON string with the
Resource Owner Password Credentials
This can be used by trusted clients by passing users credentials directly to the authorization server, in return for a token. See the References for more info and examples.
This can be used by trusted clients to use the API directly on their own behalf with any user. See the References for more info and examples.
This can be used by any client to extend a token before it expires by exchanging a refresh token for a new token without requiring the user to reenter their credentials. See the References for more info and examples.
Getting User Info
This part of the OpenID Connect specification allows a client to use the access
token to obtain the token owners identity and other claims such as
family_name. These claims must be submitted as
scopes when the authorization code is requested. Then the client can send a
GETmust have an authorization header containing the bearer token:
Authorization: "Bearer <token>"
The content of the response is JSON web token (JWT), a base-64 encoded string signed by hashing the JWT using the client secret as the key. See jwt.io for more information and available bindings.
- The response status code should be
200 OKand the content type should be
application/jwt. The status code will be
405 METHOD NOT ALLOWEDif the request does not use
403 FORBIDDENif the bearer token is missing or invalid.
- The JWT contains the user name as the subject claim,
sub, as well as any additional claims requested as scopes.
- Use the
groupsscope to get access to groups a user belongs to on the identity provider such as the administrator group.
- It is up to the client to validate that the JWT is signed correctly. The hash
algorithm is in the JWT as
- The JWT also has an issuer claim,
iss, that should be set to the name of the identity provider.
- The JWT audience claim,
aud, is the the client id.
- It's up to the client to check the time frame of the JWT using issued at
iat, expires in
exp, and not before
- The client can also confirm that the correct token was used by examining the
access token hash claim,
at_hash. Please see the the OpenID Connect Core specification for more info.
Access to resources can be limited in two ways:
- permissions (not covered in this post)
- token scopes
If a user or an application is authenticated using an OAuth 2.0 token, then
that token must have the scopes required for the desired action, regardless
of the owner's permissions or group membership! For example if an application
has been authorized by a member of the administrator group, then that token
can only be used to edit data if it has the
Scopes and Claims
Scopes can also used as claims to identify a token owner. The following scopes and claims may be available.
|groups||Access to your groups|
|name||JWT claim for user full name|
|JWT claim for user email|
|given_name||JWT claim for first name|
|family_name||JWT claim for last name|
groups scope can also be used as a claim to get the groups that the token
owner belongs to from the identity provider.