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.

See Implementing the OAuth client using a library.

For brevity, we omit minor details. For full reference, consult the following documents:

Overview

Obtaining the access token using the authorization code

The OAuth flow (technically, authorization code grant flow) consists of following steps.

  1. The client initiates the flow by creating an authorization request and directing the user's browser to the authorization endpoint.
  2. The authorization server asks the user whether they want to grant or deny access to the client that requests it.
  3. Authorization server directs the user’s browser to client’s redirect endpoint, supplying parameters which constitute an authorization response, including the authorization code.
  4. The client validates the authorization response and performs an access token request using authorization code grant.
  5. 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.

  1. The client detects that the access token is about to expire.
  2. The client performs an access token request using refresh token grant.
  3. The authorization server replies with an access token response, which contains a new access token, and, optionally, a new refresh token.
  4. 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.

ParameterDescription
response_typeMust be set to code.
client_idClient identifier obtained during client registration.
redirect_uri(Optional) URI of one of client’s registered redirection endpoints.
scopeThe 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.

ParameterDescription
codeThe 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.

ParameterDescription
errorA 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.

ParameterDescription
grant_typeMust be set to authorization_code.
codeThe authorization code received from the authorization server in the authorization response.
redirect_uriRequired, 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.

ParameterDescription
access_tokenThe access token that is issued by the authorization server. Can be used to access endpoints provided by resource servers.
token_typeThe type of access token. Only Bearer tokens are supported by Pleo authorization server and resource servers.
expires_inThe 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.

ParameterValue
grant_typeMust be set to refresh_token.
refresh_tokenRefresh 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.

ParameterExample valueNotice
response_typecodeAlways code.
client_id36e3b610-56d7-4d36-92c7-a003ca7bfc5fClient identifier received during registration.
redirect_urihttps://client.example/callbackOne of the redirect URIs registered by this client.
scopetest:test users:readA subset of scopes registered for use by this client.
stated5a2d4566e51a28ecb3b58841b39dfAn 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_challengebV7Y93L9KPvF-1R0TN2iDeZrHEm2D5OflR3O_Hf5oRQ(PKCE) Generated from code_verifier using S256 code challenge method.
code_challenge_methodS256(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.

ParameterReceived valueNotice
codeSplxlOBeZQQYbYS6WxSbIAAuthorization code issued by the authorization server. Will be used in access token request. Single-use only.
stated5a2d4566e51a28ecb3b58841b39dfOpaque 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:

ParameterExample valueNotice
grant_typeauthorization_codeAlways authorization_code in authorization code grant.
codeSplxlOBeZQQYbYS6WxSbIAAuthorization code received in authorization response.
redirect_urihttps://client.example/callbackThe same redirect URI as the one that was used in the authorization request.
code_verifierwo8H_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.

ParameterValueNotice
grant_typerefresh_tokenAlways refresh_token in refresh token grant.
refresh_tokentGzv3JOkF0XG5Qx2TlKWIARefresh 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.


What’s Next

Configure your client to work with Pleo authorization server