Implementing the OAuth client from scratch
Reference and examples for implementing OAuth with Pleo
Due to complexity of OAuth protocol and its numerous extensions, we do not recommend implementing OAuth clients from scratch. For completeness, we provide an overview of the protocol with example of it in action.
Try a library first
We strongly recommend that you try and integrate an existing open-source or commercial OAuth client solution into your application.
For brevity, we omit minor details. For full reference, consult the following documents:
- D. Hardt, The OAuth 2.0 Authorization Framework, RFC 6749, October 2012
- M. Jones, D. Hardt, The OAuth 2.0 Authorization Framework: Bearer Token Usage, RFC 6750, October 2012
- J. Reschke, The 'Basic' HTTP Authentication Scheme, RFC 7617, September 2015
- N. Sakimura, Ed., Proof Key for Code Exchange by OAuth Public Clients, RFC 7636, September 2015
Overview
Obtaining the access token using the authorization code
The OAuth flow (technically, authorization code grant flow) consists of following steps.
- The client initiates the flow by creating an authorization request and directing the user's browser to the authorization endpoint.
- The authorization server asks the user whether they want to grant or deny access to the client that requests it.
- Authorization server directs the user’s browser to client’s redirect endpoint, supplying parameters which constitute an authorization response, including the authorization code.
- The client validates the authorization response and performs an access token request using authorization code grant.
- The authorization server replies with an access token response, which contains an access token, and, optionally, a refresh token.
Refreshing the access token
Access tokens are relatively short-lived. They can be refreshed using refresh tokens that are optionally included in access token responses.
- The client detects that the access token is about to expire.
- The client performs an access token request using refresh token grant.
- The authorization server replies with an access token response, which contains a new access token, and, optionally, a new refresh token.
- Client discards the old access token and the old refresh token.
Authorization request
To start an OAuth flow, a client provides a visual prompt, usually in a form of a “Connect to Pleo” button, or similar. When this button is activated, OAuth client generates and collects several parameters, and performs an authorization request, which is done by directing user’s browser to authorization endpoint of authorization server.
The clients constructs the authorization request URI by using the following parameters.
Parameter | Description |
---|---|
response_type | Must be set to code . |
client_id | Client identifier obtained during client registration. |
redirect_uri | (Optional) URI of one of client’s registered redirection endpoints. |
scope | The scope of access request. Requested scope must form a subset of the scope that was registered for this client. |
state | (Optional) An opaque value used by the client to maintain state between issuing an authorization request and receiving an authorization response. |
code_challenge | (PKCE) Code challenge — a value derived from code verifier using the chosen code challenge method. |
code_challenge_method | (PKCE) Code challenge method. Must be set to S256 . |
Upon receiving an authorization request, authorization server presents user with the authorization screen, showing the information about a client, and the details of authorization request that it makes, including requested permissions. User can make a choice to either authorise or deny access. The result of that choice is conveyed back to the client in an authorization response. which is done by directing user’s browser back to to client’s redirect endpoint.
PKCE
Parameters marked with (PKCE) are defined in PKCE extension to core OAuth protocol. They are mandatory, except for clients which don’t support PKCE, and were marked as such during registration.
PKCE generator
You can use free online tools, such as https://tonyxu-io.github.io/pkce-generator/, to generate parameters defined by PKCE extension, for the purposes of testing and validating your OAuth client implementation.
For full reference on PKCE, consult RFC 7636.
Authorization response
After completing its interaction with the resource owner, the authorization server directs the resource owner's user-agent back to the client, using one of the previously established redirect endpoints registered to a client.
The authorization response is received as an HTTP request to a client’s redirect endpoint. Authorization response can represent either a successful authorization of access, or an error.
After receiving an authorization response, client validates it. If the authorization response represents an authorization error (usually, because the end-user denied the authorization request), or is invalid, client can show a corresponding error message, and may prompt the user to try the authorization request again.
Success response
The authorization response representing a successful authorization contains the following parameters.
Parameter | Description |
---|---|
code | The authorization code generated by the authorization server. Used by the client in the access token request. Can be used only once. |
state | (Required, if the authorization request contained a state parameter) The exact value of state parameter sent by the client in the authorization request. If present, must be validated by the client before performing an access token request. Can be used by the client to restore state after redirection |
If the authorization response is valid and represents successful authorization, client then may perform an access token request to the authorization server, supplying the received authorization code
.
Error response
If the authorization response represents an error response, or is invalid, the client must not perform an access token request, and should convey a corresponding error message to the end-user.
The error response contains the following parameters.
Parameter | Description |
---|---|
error | A single error code, usually access_denied . |
state | (Required, if the authorization request contained a state parameter) The exact value of state parameter sent by the client in the authorization request. |
error_description | (Optional) Human-readable error description to assist the developer of the client. |
error_uri | (Optional) An URI identifying a web page containing detailed description of the error. |
Access token request (authorization code grant)
An access token request is a HTTP request directly from the client to the authorization server, with the following parameters.
Parameter | Description |
---|---|
grant_type | Must be set to authorization_code . |
code | The authorization code received from the authorization server in the authorization response. |
redirect_uri | Required, if the redirect_uri parameter was included in the authorization request, in which case their values must be identical. |
code_verifier | (PKCE) A code verifier value that was used to generate a code challenge. |
Access token request must be authenticated using client_secret_basic
authorization method, that is, an Authorization
HTTP header, using Basic
authorization scheme and corresponding client credentials: client identifier and client secret.
Access token response
If the access token request is valid, the authorization server returns an access token response, providing following parameters, encoded as a JSON object.
Parameter | Description |
---|---|
access_token | The access token that is issued by the authorization server. Can be used to access endpoints provided by resource servers. |
token_type | The type of access token. Only Bearer tokens are supported by Pleo authorization server and resource servers. |
expires_in | The lifetime in seconds of the access token. |
refresh_token | (Optional) The refresh token, which can be used to obtain new access tokens, to replace expiring ones. |
scope | (Optional) The scope of the access token. If not present, is identical to scope requested by the client in the authorization request. |
An access token is valid for the duration specified by expires_in
, after which it will be rejected by the resource servers. A new access token can be obtained automatically using a refresh token.
Access token request (refresh token grant)
For security, access tokens have a relatively short lifetime, and cannot be used to access APIs after expiration. However, authorization server may issue a refresh token along with the access token. A refresh token can be used to obtain a new access token to replace an expiring one.
An access token request using refresh token grant uses the following parameters.
Parameter | Value |
---|---|
grant_type | Must be set to refresh_token . |
refresh_token | Refresh token received in the last access token response. |
Access token response will contain a new access token and, optionally, a new refresh token. After receiving an access token response, the client must discard old access and refresh tokens, and use the new ones instead.
An access token response may not include a refresh token, in which case a new access token cannot be obtained automatically. This can happen because the authorization server detects conditions that require manual intervention from resource owner, who should be informed to re-connect the client to Pleo.
Example
This example uses registration data of the client described in OAuth client registration, and illustrates the full flow of running an OAuth authorization code grant, as well as refreshing an access token using the refresh token grant.
Authorization request
A client implements a web page that serves as a starting point for initiating the authorization with Pleo. In our example, this web page displays “Connect to Pleo” button. Clicking this button activates the OAuth client library.
OAuth client library then fills the parameters to perform an authorization request with the following parameters.
Parameter | Example value | Notice |
---|---|---|
response_type | code | Always code . |
client_id | 36e3b610-56d7-4d36-92c7-a003ca7bfc5f | Client identifier received during registration. |
redirect_uri | https://client.example/callback | One of the redirect URIs registered by this client. |
scope | test:test users:read | A subset of scopes registered for use by this client. |
state | d5a2d4566e51a28ecb3b58841b39df | An opaque value which helps restore the client context later. |
code_verifier (not sent) | wo8H_PzaG9eH6_wycgwJmGcYG-wdEkm5VulQBCJvA7I | (PKCE) Generated randomly, only used once per each authorization request. Kept secret until later. |
code_challenge | bV7Y93L9KPvF-1R0TN2iDeZrHEm2D5OflR3O_Hf5oRQ | (PKCE) Generated from code_verifier using S256 code challenge method. |
code_challenge_method | S256 | (PKCE) Always S256 . |
This library then performs a HTTP redirect to Pleo authorization server, thus executing an authorization request. This can be done, for example, using HTTP 302 status code with the Location
header containing the URL of the authorization endpoint with all the parameters.
An example of a HTTP redirect from the client to the authorization server:
HTTP/1.1 302 Found
Location: https://auth.pleo.io/oauth/authorize
?response_type=code
&client_id=36e3b610-56d7-4d36-92c7-a003ca7bfc5f
&redirect_uri=https%3A%2F%2Fclient.example%2Fcallback
&scope=test%3Atest+users%3Aread
&state=d5a2d4566e51a28ecb3b58841b39df
&code_challenge=bV7Y93L9KPvF-1R0TN2iDeZrHEm2D5OflR3O_Hf5oRQ
&code_challenge_method=S256
Authorization response
User’s browser is redirected to Pleo authorization server, which performs the necessary user authentication and asks them to authorize “Example Client”. After user grants authorization, authorization server redirects user’s browser back to client — specifically, to redirect endpoint.
HTTP/1.1 302 Found
Location: https://client.example/callback
?code=SplxlOBeZQQYbYS6WxSbIA
&state=d5a2d4566e51a28ecb3b58841b39df
Client redirect endpoint is controlled by the OAuth client library, which can then proceed with the parameters it received in the authorization response.
Parameter | Received value | Notice |
---|---|---|
code | SplxlOBeZQQYbYS6WxSbIA | Authorization code issued by the authorization server. Will be used in access token request. Single-use only. |
state | d5a2d4566e51a28ecb3b58841b39df | Opaque value from the authorization request sent back by the authorization server. Must be recognised and validated by the client. |
If state
is present, client compares it to a known value that it has sent during the authorization request, to make sure they match. It can also use this value to restore its own state.
Access token request (authorization code grant)
OAuth client library performs an access token request: an authenticated request to receive an access token in exchange for the authorization code received in authorization response.
Access token request rely on client authentication, which is performed using the Basic
HTTP authentication scheme, defined in RFC 7617.
Parameters of the request:
Parameter | Example value | Notice |
---|---|---|
grant_type | authorization_code | Always authorization_code in authorization code grant. |
code | SplxlOBeZQQYbYS6WxSbIA | Authorization code received in authorization response. |
redirect_uri | https://client.example/callback | The same redirect URI as the one that was used in the authorization request. |
code_verifier | wo8H_PzaG9eH6_wycgwJmGcYG-wdEkm5VulQBCJvA7I | (PKCE) Code verifier generated before the authorization request, now revealed to the authorization server. |
POST /oauth/token HTTP/1.1
Host: auth.pleo.io
Authorization: Basic MzZlM2I2MTAtNTZkNy00ZDM2LTkyYzctYTAwM2NhN2JmYzVmOjcwNzcxZjNjYmY0NzJiYTkxNmFlZmQyMWJlOWM3YQ==
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Fcallback
&code_verifier=wo8H_PzaG9eH6_wycgwJmGcYG-wdEkm5VulQBCJvA7I
Notice that request parameters are sent using application/x-www-form-urlencoded
content type, and not application/json
.
Access token response
After receiving and validating the access token request, the authorization server responds back to the client with the access token response.
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token": "MTZhNjExbTR2MXI0bjRiNDgyMjZrOTU4NTg2YzNl",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA"
}
The client stores the access token, and notices its lifetime. Old refresh token is replaced by the new one (or discarded, if no new refresh token is present).
The client now can perform API requests using the access token.
Access token request (refresh token grant)
A new access token can be obtained to replace an expiring one, using a refresh token grant.
Parameter | Value | Notice |
---|---|---|
grant_type | refresh_token | Always refresh_token in refresh token grant. |
refresh_token | tGzv3JOkF0XG5Qx2TlKWIA | Refresh token received in the last access token response. Can only be used once. |
POST /oauth/token HTTP/1.1
Host: auth.pleo.io
Authorization: Basic MzZlM2I2MTAtNTZkNy00ZDM2LTkyYzctYTAwM2NhN2JmYzVmOjcwNzcxZjNjYmY0NzJiYTkxNmFlZmQyMWJlOWM3YQ==
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
Note that the refresh token can be used only once, after which it must be replaced by the newly received refresh token. If no replacement refresh token was received back in the response, this means that the authorization session can no longer be refreshed without user intervention. A client then should prompt the end user to start a new authorization session.
Updated 3 months ago