This document is intended to be a simplified version of the OAuth 2.0 specification. In particular it has been written with implementors in mind, and as such attempts to trim the spec down to just what you need to implement an OAuth provider or client. It is necessarily not complete, but attempts to introduce spec requirements in the same order in which the protocol proceeds in practise, with everything you need to know about each protocol endpoint brought together in one place rather than scattered across a large document.
Caveat emptor: some details have been deliberately left out because the author considered them detrimental to an easy understanding of how the protocol should be used. Almost everything in the spec is suffixed with, 'or, do whatever you want,' so I doubt this has done much to damage the document's accuracy.
It is recommended that implementors read the Security Considerations in the original specification.
There are four entities in OAuth:
- Resource owner - an entity capable of granting access to protected resources
- Resource server - a server storing and mediating access to protected resources
- Client - an application that wants access to the resource owner's resources
- Authorization server - server that issues tokens to clients
+--------+ +---------------+
| |--(A)- Authorization Request ->| Resource |
| | | Owner |
| |<-(B)-- Authorization Grant ---| |
| | +---------------+
| |
| | +---------------+
| |--(C)-- Authorization Grant -->| Authorization |
| Client | | Server |
| |<-(D)----- Access Token -------| |
| | +---------------+
| |
| | +---------------+
| |--(E)----- Access Token ------>| Resource |
| | | Server |
| |<-(F)--- Protected Resource ---| |
+--------+ +---------------+
- Authorization code
- Implicit
- Resource owner password credentials
- Client credentials
- Extension types
The client redirects to the authorization server, which authenticates the resource owner and obtains authorization, then redirects to the client with an authorization code. The client then exchanges the code for an access token by supplying its credentials. This allows client to authenticate separately and means the access token never is exposed to the resource owner's user agent.
Optimized for in-browser JS clients. Instead of an authorization code, an access token is issued immediately without client authentication. Identity is handled using redirect URI. Because the access token is returned via a redirect rather than as the result of a server-side call, it is exposed to the resource owner and any other software with access to the user agent.
Username and password are used instead of an authorization code to obtain an access token. Should only be used for highly trusted clients or when other types are not available. Username and password are only used to get an access token and are not stored. This flow can also be used to migrate legacy systems to OAuth by exchanging stored user credentials for an access token.
The client supplies its own credentials to get an access token. Used when the client and resource owner are the same entity. This flow must only be used by confidential clients (defined below).
The client gets an access token by declaring it's using an extension type, identified by an absolute URI, and supplying any parameters required by that type. In earlier drafts of the spec this mechanism was referred to as 'assertions' but its scope has since broadened.
Both types of tokens are opaque to the client. Access tokens may be identifiers used to retrive authorization data, or self-contain the data using a signed representation. Refresh tokens are identifiers.
More detailed information on different token types appears at the end of this document.
+--------+ +---------------+
| |--(A)------- Authorization Grant --------->| |
| | | |
| |<-(B)----------- Access Token -------------| |
| | & Refresh Token | |
| | | |
| | +----------+ | |
| |--(C)---- Access Token ---->| | | |
| | | | | |
| |<-(D)- Protected Resource --| Resource | | Authorization |
| Client | | Server | | Server |
| |--(E)---- Access Token ---->| | | |
| | | | | |
| |<-(F)- Invalid Token Error -| | | |
| | +----------+ | |
| | | |
| |--(G)----------- Refresh Token ----------->| |
| | | |
| |<-(H)----------- Access Token -------------| |
+--------+ & Optional Refresh Token +---------------+
Though 302 is used in the spec, any workable method of redirecting the client is acceptable.
Clients must provide:
- Client type
- Confidential - can keep their credentials secure, e.g. server-side apps
- Public - cannot keep credentials secure, e.g. JS/native apps
- Redirect URI(s)
- If the client cannot pre-regsiter its complete redirect URI, it must at least register the scheme, authority and path. The client can still vary the query string in this URI when obtaining authorization.
- The client can register multiple redirect URIs.
- The provider should never redirect to an unregistered URI.
- Server-defined metadata e.g. name, website, description, logo
All public clients, and confidential clients using the implicit grant type, must pre-register with the provider. The provider should (not must) require other client types to register as well.
On registration, client receives:
- Client identifier - unique string identifying the client, not secret
- Client credentials - if confidential client, get a password, key pair, etc.
Providers may issue credentials to public clients but should not trust them.
Providers may elect to respond to unregistered clients at their own discretion, for example see the remoteStorage protocol.
An OAuth provider must have:
- An authorization endpoint, which the client redirects to when it needs the
user to grant authorization.
- Used by the authorization code and implicit flows
- May include
application/x-www-form-urlencoded
query component - Must not include fragment component
- Must respond to
GET
, may respond toPOST
- A token endpoint, which the client uses to obtain access tokens
- Used by all flows except the implicit grant type
- May include
application/x-www-form-urlencoded
query component - Must not include fragment component
- Must respond to
POST
An OAuth client must have:
- A redirection endpoint, which the provider redirects to with the user's
authorization code
- May include
application/x-www-form-urlencoded
query component - Must not include fragment component
- Must respond to
GET
- Used by the authorization code and implicit flows
- May include
In general, all endpoints must be accessed over TLS to protect credentials transferred over the wire. (This requirement is a MUST for the provider and a SHOULD for the client.)
Query parameters must not appear more than once in any request, and should be ignored if sent without a value. Unknown parameter names should be ignored.
In the authorization code and implicit flows, the client begins by redirecting the user agent to the provider's authorization endpoint. It includes the following parameters:
response_type
- required, can be one of:code
causes the provider to issue an authorization code, which the client must send to the token endpoint along with its credentials to obtain an access token.token
causes the provider to issue an access token immediately (implicit flow). The client can immediately use this token without authenticating through the token endpoint.- Extension types may be defined that contain space (
%20
) delimited unorderd list of values. The meaning of these is defined in other specs.
client_id
- required, the client's unique identifier.redirect_uri
- required unless the client has registered a single complete redirection endpoint. If it has registered multiple endpoints, an incomplete endpoint or no endpoint at all, this parameter is required. When present, the provider must check that at least one of the client's registered URIs matches this value. (See RFC3986 section 6.)scope
- optional, space-separated list of scope names. The provider should show the owner a readable list of the scopes the client has asked for. If no scope is requested, the provider must assume an implicit default scope or treat the request as invalid.state
- optional (but recommended) string value used by the client to maintain state between the request and the callback. The provider must echo this value unmodified when it redirects back to the client. Can be used to prevent cross-site request forgery (CSRF).
The provider returns its response either by displaying a page to the resource
owner (in the case of some types of error) or by redirecting to the client's
redirection endpoint. The response contains a series of parameters expressed
in application/x-www-form-urlencoded
format. These parameters appear in the
query string if the client sent response_type=code
, or in the fragment if the
client sent response_type=token
. Since some user agents do not support
fragments in the Location
header, it may be necessary to redirect via other
means, for example a form
whose action
refers to the required URI.
If the client's authorization request was valid, and the resource owner successfully authenticates and grants access, the provider redirects back to the client's redirection endpoint. It should warn the resource owner if the redirection endpoint does not use TLS since leaking a code or access token affects the security of the protected resources. This is particularly important if the client is using the provider as a 3rd-party authentication service a-la 'Sign in with Facebook'.
The provider includes the following url-encoded parameters in the redirect URI sent to the client:
code
- required if the client sentresponse_type=code
. A unique token representing the owner's access grant to the client. It is recommended this token expire after at most 10 minutes, but the code must expire at some point. The client cannot use this code more than once to obtain an access token. If the token is used more than once the provider should revoke tokens derived from it, if possible.access_token
- required if the client sentresponse_type=token
. A token representting the resource owner's access grant to the client, encapsulating the grant's scope(s) and duration. The client uses this token to access protected resources.token_type
- required if the client sentresponse_type=token
. Case- insensitive value that tells the client what type of token is being issued and how to use it.expires_in
- recommended if the client sentresponse_type=token
. The lifetime in seconds of the access token. If omitted, the provider should document the default value.scope
- if applicable, a space-separated list of the scopes that the resource owner granted the client access to. This may be a subset of the scopes requested by the client, based on the provider's policies and the resource owner's instructions. The server must include this if it differs from what the client requested.state
- the same value that the client included in the authorization request.
If the client responds to the redirection endpoint with an HTML page (rather
than redirecting further), it should not include any 3rd-party JavaScript in the
page since the authorization code or access token is visible to all JS code via
the window.location
object.
If the authorization request fails due to an invalid redirect_uri
or
client_id
, the provider must inform the resource owner of the error and must
not redirect to the supplied URI. If the request is invalid for any other reason
(e.g. the resource owner denied the request), and the provider has enough
information to redirect to the client, it should do so.
The provider will include the following url-encoded parameters when redirecting
to the client. Chars in these parameters must be in the range %x20-21 / %x23-5B / %x5D-7E
.
error
- required, one of:invalid_request
- the request was missing a required parameter, includes invalid values or is otherwise malformedunauthorized_client
- the client cannot request authorization via this methodaccess_denied
- the resource owner denied the requestunsupported_response_type
- the requestedresponse_type
is not supportedinvalid_scope
- the requestedscope
is invalid, unknown, or malformedserver_error
- the server encountered an unhandled error during processingtemporarily_unavailable
- current unable to handle the request
error_description
- optional text explanation of the errorerror_uri
- URI of a page giving more information about the errorstate
- the same value that the client included in the authorization request
e.g.
HTTP/1.1 302 Found
Location: https://client.example.com/cb?error=access_denied&state=xyz
In all flows except the implicit grant type, the client calls the provider's token endpoint to exchange some set of credentials for an access token. This typically involves the client authenticating to guard against codes and tokens being leaked or clients being compromised.
Client can use HTTP Basic authentication when obtaining an access token. It uses
its url-encoded client_id
as the username and its url-encoded client_secret
as the password. e.g.:
Authorization: Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3
The client can include client_id
and client_secret
in the request body.
Clients should only do this if they're incapable of using HTTP Basic auth. e.g.:
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
&client_id=s6BhdRkqt3&client_secret=7Fjfp0ZBr1KtDRbnfVdmIw
The client must not put client_id
or client_secret
in the URI when
authenticating.
This request must be performed using TLS. The server must protect the
client_secret
against brute force attacks.
If the client was never issued with a client_secret
(e.g. because it's a
public client) it only needs to send client_id
in the token request. This
should not be treated as trustworthy and should only be used for informing the
user, gathering stats, etc.
The server may support other authentication mechanisms if it wants to.
As well its authentication credentials, the client passes the following url-encoded parameters in the body of the POST request:
grant_type
- required, one of:authorization_code
if the client usedresponse_type=code
previouslypassword
if using the resource owner password credentials flowclient_credentials
if using the client credentials flowrefresh_token
if the client was previously issued with a refresh token- An absolute URI indicates an extension type
code
- required ifgrant_type=authorization_code
. The value of thecode
parameter given to the client by the provider in the previous step.username
- required ifgrant_type=password
.password
- required ifgrant_type=password
.redirect_uri
- required if this value was included in the authorization request. Must be identical to the previous value. Not required if there was no authorization request, for example ifgrant_type=password
.scope
- optional, space-separated list of scope names. If no scope is requested, the provider must assume an implicit default scope or treat the request as invalid. The client includes the scope as this stage if there was no previous authorization request, for example ifgrant_type=password
.
If using an extension type, the client must include whichever parameters are required by that type, for example for SAML 2.0 assertions:
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Asaml2-
bearer&assertion=PEFzc2VydGlvbiBJc3N1ZUluc3RhbnQ9IjIwMTEtMDU
The provider must, where applicable:
- authenticate the client if it was issued with credentials
- check the authorization code was issued to that client
- verify the authorization code is valid
- check the refresh token is valid and was issued to that client
- if the
redirect_uri
param was used in the authorization request, check it is present in the token request and has the same value - validate the given scope(s)
- carry out any validation required by an extension type
The provider must return a JSON document using the application/json
content
type and the Cache-Control: no-store
and Pragma: no-cache
headers. The
client must ignore parameters it does not recognize.
The status code is 200 for a successful response, and 400 or 401 for an error response.
e.g.:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
If the request is valid, the server issues a 200 response containing a JSON document with the following fields:
access_token
- a token representting the resource owner's access grant to the client, encapsulating the grant's scope(s) and duration. The client uses this token to access protected resources.token_type
- required, case-insensitive value that tells the client what type of token is being issued and how to use it. This will either be a registered name (e.g.bearer
,mac
) or an absolute URI.expires_in
- recommended, the lifetime in seconds of the access token. If omitted, the provider should document the default value.refresh_token
- optional, a token that can be used to obtain new access tokens using the same authorization grant.scope
- if applicable, a space-separated list of the scopes that the resource owner granted the client access to. This may be a subset of the scopes requested by the client, based on the provider's policies and the resource owner's instructions. The server must include this if it differs from what the client requested.
If the request is not valid, the server issues a 400 response containing a JSON document with the following fields:
error
- required, one of:invalid_request
- the request was missing a required parameter, includes invalid values or is otherwise malformedinvalid_client
- the client did not authenticate successfully. The provider may return a 401 to indicate which authentication methods are supported. If the client attempted to authenticate via theAuthorization
header, the provider must respond with a 401 and use theWWW-Authenticate
header matching the authentication scheme used by the client.invalid_grant
- the provided authorization grant (e.g. authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.unauthorized_client
- the client cannot request authorization via this grant typeunsupported_grant_type
- the requestedgrant_type
is not supportedinvalid_scope
- the requestedscope
is invalid, unknown, or malformed
error_description
- optional text explanation of the errorerror_uri
- URI of a page giving more information about the error
Once the client has obtained an access token it can use it to make authenticated requests on the resource owner's behalf. The resource server checks the token is valid, not expired, and carries sufficient scope to access/modify the requested resource.
The method by which the token is embedded in the request depends on the
token_type
the token was issued with, but typically involves data transferred
in the Authorization
header. The particular syntax, as well as the format of
error responses, is defined by other specs.
Clients must not use token types that they do not understand. Some examples of standardized token types follow.
These tokens have token_type=bearer
. They are opaque values that either
encode the authorization using a cryptographic signature, or are identifiers
that refer to authorization information stored on the provider's servers. If the
latter, they should have negligible probability (must be less than 2^-128,
preferably less than 2^-160) of being guessed.
Bearer tokens may be transmitted using the Authorization
header using the
Bearer
scheme. They must only be transmitted via TLS. They are confined to the
character set used in base64-encoding, but are not actually encoded as such
before transmission - they are included literally in the request.
GET /resource/1 HTTP/1.1
Host: example.com
Authorization: Bearer mF_9.B5f-4.1JqM
They may be embedded in the body of an application/x-www-form-urlencoded
request using the access_token
parameter, if all the following are true:
- The request includes the header
Content-Type: application/x-www-form-urlencoded
- The entity body is correctly url-encoded
- The entity body is single-part (e.g. no file uploads)
- The entity body consists only of ASCII characters
- The HTTP verb has defined semantics for the body, e.g.
GET
is not allowed
Finally, the token may be included as a query string parameter. Clients must
send the header Cache-Control: no-store
with such requests, and the provider
should return the header Cache-Control: private
with 200 responses.
Clients should use, in order of preference for security reasons: the
Authorization
header, entity body encoding, then query-string encoding. They
should use each scheme only if they are incapable of using more desirable scheme.
Providers should make sure tokens do not appear in HTTP logs.
If the token is not valid for accessing the requested resource, the provider
returns an error using the WWW-Authenticate
header, e.g.:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="example",
error="invalid_token",
error_description="The access token expired"
The header uses the Bearer
scheme and may include the following parameters.
The provider should not include specific error information if the request
contained no (or unrecognized) authentication data.
realm
scope
- a space-separated list of scopes required to access the resourceerror
- if the request contained an access token that was not valid, this value can be one of the following. Associated status codes are given in brackets.invalid_request
[400] - required parameter missing, request malformedinvalid_token
[401] - the token is expired, revoked, malformed, etc.insufficient_scope
[403] - the token does not have all the scope(s) required to access the resource
error_description
- human-readable explanation of theerror
error_uri
- URI of a page containing more information about the error
In addition to the statuses 400, 401 and 403 listed above, the server may return 405 (Method Not Allowed) in response to a failed request.
These tokens have token_type=mac
and are issued as a token along with the
mac_key
and mac_algorithm
parameters. They must be issued over TLS.
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"SlAV32hkKG",
"token_type":"mac",
"expires_in":3600,
"refresh_token":"8xLOxBtZp8",
"mac_key":"adijq39jdlaska9asud",
"mac_algorithm":"hmac-sha-256"
}
access_token
and mac_key
are opaque values. mac_algorithm
may be one of
hmac-sha-1
or hmac-sha-256
; this tells the client how to calculate MACs when
using this token type. These values must not include characters other than
%x20-21 / %x23-5B / %x5D-7E
.
MAC tokens are transmitted using the Authorization
header using the MAC
scheme. The client calculates a MAC based on the access token parameters and the
properties of the request, and embeds the result in this header, e.g.:
GET /resource/1?b=1&a=2 HTTP/1.1
Host: example.com
Authorization: MAC id="h480djs93hd8",
ts="1336363200",
nonce="dj83hs9s",
mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="
ext="an optional value"
These requests can be made over a plaintext connection.
The client constructs the request as follows. It first generates the current
Unix timestamp (ts
) and a random string (nonce
). It then generates a
normalized request string (NRS) by concatenating the follow values separated
by a newline 0x0A
character:
- The current Unix timestamp
ts
- The nonce
nonce
- The uppercase HTTP method e.g.
GET
,POST
, etc. - The request URI
- The hostname as contained in the
Host
header - The port number as contained in the
Host
header, or the default port number for the request scheme (80 for HTTP, 443 for HTTPS) - The value of the
ext
Authorization
field if present
For example the HTTP request
POST /request?b5=%3D%253D&a3=a&c%40=&a2=r%20b&c2&a3=2+q HTTP/1.1
Host: example.com
Hello World!
along with the timestamp 264095:7d8f3e4a
, nonce 7d8f3e4a
and ext
value
a,b,c
produces the NRS:
264095\n
7d8f3e4a\n
POST\n
/request?b5=%3D%253D&a3=a&c%40=&a2=r%20b&c2&a3=2+q\n
example.com\n
80\n
a,b,c\n
The client then calculates mac = HMAC(key, text)
where HMAC
is either
hmac-sha-1
or hmac-sha-256
as required by the provider, key
is the issued
mac_key
and text
is the NRS value. It then constructs the Authorization
header value by including the ts
, nonce
, mac
, ext
and id
values, where
id
is the value of access_token
issued by the provider that identifies the
key being used so the provider can verify it.
The provider must verify the MAC by using the id
to look up the key in its
database and recalculating the MAC by the above steps. It must check that the
(ts,nonce,mac)
combination has never been received before. It must also
verify that the token has not expired, has not been revoked, and covers the
scope(s) required by the requested resource.
The server can reject requests whose timestamps are beyond a certain threshold, so that it does not have to store an indefinite number of MACs to prevent replay attacks.
The first time the provider receives a request with a given key identifier id
,
it stores the request time delta, the difference between the request timestamp
ts
and the server's clock. For every subsequent request using the same id
,
it calculates the adjusted request time by applying the delta to the request
timestamp to adjust the time to its own clock. If the adjusted time is too far
in the past (allowing for reasonable network latency) the request is rejected.
If the token verification fails, the provider returns a 401 response with the
WWW-Authenticate
header, e.g.:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: MAC error="The MAC credentials expired"