Authorization Code Grant

The Authorization Code Grant is an OIDC-compliant authentication and authorization flow. It implements strong end user authentication, and is used when an application needs to access resources owned by an end user.

This manual describes how to acquire access tokens using the Authorization Code Grant, and shows how the token can be used to call an OP API. On this page, you will also find information on how to use the grant in our sandbox.

Currently, this flow applies to Accounts V3.0. Other APIs (e.g. PSD2 APIs) will specify their required flows in their API documentation.

Overview

auth flow styled

Getting started

Prerequisites

  • Production & sandbox: A registered application on OP Developer, along with a client ID and client secret ("App API key" and "App API secret", respectively).
  • Production & sandbox: At least one redirect URI for the application has been registered on OP Developer (Not required when using static tokens).
  • Production: A registered JWKS endpoint for supplying public keys to the auth server (mocked with static keys in sandbox).

Full instructions on implementing the JWKS endpoint will be provided when negotiation production access.

If you are only interested in mock authentication with static authorization tokens, take any of the tokens listed in the next section and jump over to part 5.

In sandbox

To help developers in different stages of development, we support two methods for simulating authentication and authorization in our sandbox.

TypeExplanation
1. Static tokensAuthorization with static access tokens
2. Full mock flowThe authorization code grant flow, as described in this manual: from JWT requests to authentication and authorization UI, to using access and refresh tokens for calling the sandbox API.

1. Static tokens

The quick-and-dirty method is to skip straight to step 5 of this manual and call the API using a one of the following as a bearer token:

Token
6c18c234b1b18b1d97c7043e2e41135c293d0da9
b6910384440ce06f495976f96a162e2ab1bafbb4
7a66629ddf3691a66eb6466ab7a9f610de531047
3af871a0e3ebfc46f375ff2b63d1414982bd4f76

2. Full mock flow

The full mock flow imitates the Authorization Code Grant as described in this manual. There are a two differences compared to production:

  • JWKS endpoint is not required - fixed keyset used for signatures and verification
  • Sign in and authorize with these credentials:

    • user name: 796565560
    • password: 1122
    • key code: 1122

Next, we'll explain how to complete the authorization flow.

1. Prepare the authorization request

First, construct a JWT request. The JWT must be signed with a private key using RS256. In production, you must have registered a JWKS endpoint so that your signature can be verified. In sandbox, use our static keyset for signing.

jwt.io provides a wonderful UI for creating test JWTs, and lists common libraries to help with JWTs.

1.1 Construct the request content

A JWT consists of three parts: a header, a payload, and a signature. Below is a sample header and payload, which you can use as a starting point when constructing your JWT.

Header
{
  "alg": "RS256",
  "typ": "JWT"
}
Payload
{
  "aud": "op_open_oauth",
  "scope": "openid accounts accounts:transactions",
  "iss": "qfviLNoGNADLknGAEjl",
  "response_type": "code",
  "state": "1111-2222-3333-4444",
  "redirect_uri": "http://localhost:8080/redirect",
  "iat": 1546860754,
  "exp": 1546960754,
  "client_id": "qfviLNoGNADLknGAEjl",
  "nonce": "040d70e8-1272-433b-adb2-293fd2f27c71"
}
FieldTypeExplanation
audstringIdentifies the intended audience of the JWT, i.e. the OP authentication and authorization service. Set to op_open_oauth .
scopestringRequested scopes as a space-delimited list of scope identifiers. These define the level of access that the client app requests to the end user's data. The openid scope is required in all requests. The scopes for Accounts V3.0 are accounts (account list and basic information) and accounts:transactions (transaction list).
issstringIssuer of the JWT request. This field contains the client ID, which is equivalent to APP_API_KEY obtained from OP Developer.
response_typestringIdentifies the auth flow type. The only allowed value is "code", indicating the access code flow.
redirect_uristringThe URI to which the authorization service will redirect the user after authentication. This must be an absolute URL, and must be an exact match with a redirect URI that has been registered for your application.
statestringA string value that will later be returned to the client as a query parameter. Allows the client to compare and validate the request and response.
iatDate/timestampThe time at which the token was issued. UNIX time stamp (in seconds).
expDate/timestampExpiration time: The JWT must not be accepted for processing after this time stamp.
noncestringOptional . A string used for correlating an ID token with a client session. If used, it must be included both in the payload and as a query parameter.
client_idstringClient ID of the TPP application. This is the APP_API_KEY received from OP Developer.

Build and sign the JWT

Once the header and body of the JWT are ready, the token string must be completed following these steps:

  1. Base64Url-encode the header.
  2. Base64Url-encode the body.
  3. Append the Base64Url-encoded body string to the Base64Url-encoded header, using a dot as a separator.
  4. Copy the resulting string and sign it with your client secret using RS256 and our fixed keyset. This is your signature.
  5. Append the signature to the string you created in step 3, using another dot as a separator.

At this point, you have a complete, signed JSON Web Token.

For more information, see the JWT spec.

2 Authentication and authorization

Authentication and authorization take place between the auth server and the end user. This section explains how to take the user to authentication.

2.1 Redirection to the login page

Once you have built the JWT request, redirect the user to the authorization page. The JWT request must be attached as a query parameter. The request must have at least the following query parameters:

  • request - The full JWT request
  • response_type
  • client_id
  • scope
  • redirect_uri
  • state

In addition, if you use the nonce parameter in the payload, it must be included in the query as well.

Example below (line breaks for legibility only):

https://sandbox.apis.op-palvelut.fi/oauth/v1/authorize
?request=<your_JWT_string>
&response_type=code
&client_id=******
&scope=openid%20accounts%20accounts%3Atransactions
&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fredirect
&state=1111-2222-3333-4444

Remember that nonce is not required, but if it is used, it must be present in both the JWT payload and the query. You may include the iat and exp fields as query parameters. They must match with the values given in the JWT request, or the request will fail.

The authentication server redirects the user to a login page. After this, the user sees the details of the authorization being requested, e.g. scope and the resources involved.

The user will be able to view, modify, or reject the authorization.

In sandbox

Log in using the following credentials:

  • username: 79565560
  • password: 1122
  • key code: 1122

3. Redirection to return URL with auth code

Upon successful authorization, the OAuth service redirects the client to the URL supplied in the redirect_uri parameter of the JWT request.

You must have registered at least one redirect URI for your application, and the redirect URI supplied in the request must match one of these registered URIs.

The authorization code will be supplied as a query parameter named code, such as in the following example:

https://localhost:8080/redirect?state=<state>&code=<access_code>

The state parameter will contain the value originally submitted in the state field of the JWT request.

Errors

If authentication or authorization fail, the redirection will be redirected as follows:

https://localhost:8080/redirect?state=<state>&error=<error_description>

The error parameter will describe the error, allowing you to communicate the source of the error to the end user.

For example, if the end user interrupts the authorization process, the error descriptor will contain the message access_denied.

ErrorDescription
server_errorThere was an error in the backend.
invalid_requestThe request is faulty or malformed. Ensure that the values in the JWT request and query match, and that the redirect uri matches with that which you have registered on OP Developer.
access_deniedThe user has terminated the authorization process.

4. Retrieve access and refresh tokens

In this step, the TPP uses the freshly-received authorization code to request access and refresh tokens, as shown below.

The TPP application must present a valid client ID and client secret when requesting tokens. These credentials must be provided in the request body.

Token request

POST /oauth/v1/token HTTPS/1.1
Host: sandbox.apis.op-palvelut.fi
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
x-api-key: **********

grant_type=authorization_code&code=********&client_id=********&client_secret=********

Bear in mind that client_id is your app's API key, and client_secret your app's API secret.

Return value following a successful token request

{
    "access_token":"COu9bPywEnODHHMzPDE6",
    "refresh_token":"Az62ac8DyThfrgTxzmhSNloAUOl71ynnAeOCHkwM",
    "scope": [
        "accounts",
        "accounts:transactions"
      ],
    "id_token": "eyJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJleGFtcGxlLWNsaWVudCIsInN1YiI6IldjY2FLblJOVmRFVTZVZ25hS09vWVE3Z244NHZoaDJNM1JOMTl6Z3kzZzgiLCJpc3MiOiJodHRwOlwvXC9sb2NhbGhvc3Q6ODA4M1wvb2F1dGgiLCJuYW1lIjoiRXJra2kgRWR1c3RhIiwiZXhwIjoxNTQ0MzU2NDYyLCJpYXQiOjE1NDE3NjQ0NjJ9.VR2MxSLcXqJCdvby9fsWcklB4As1eeZYAz432x0-9ZBp9IRWb2DZGhapjkejEDbe3mQF4M6XS5ASiG-8REPF6Q",
    "token_type":"Bearer",
    "expires_in":900,
}
FieldTypeExplanation
access_tokenstringThe access token. Note that the string had no fixed length and may be long.
refresh_tokenstringRefresh token for requesting additional access tokens. Has no fixed length and be quite long.
scopearrayArray of strings that define the scopes of the access token.
id_tokenstringToken string containing information about the user.
token_typestringDefines the type of the token. Always gets the value Bearer .
expires_inintegerThe number of seconds after which this token expires.

Token request cURL template

curl -k https://sandbox.apis.op-palvelut.fi/oauth/v1/token \
-H "Accept:application/json" \
-H "Content-Type:application/x-www-form-urlencoded" \
-H "Cache-Control:no-cache" \
-d "grant_type=authorization_code&code=********&client_id=********&client_secret=********"

Token refresh cURL template

curl -k https://sandbox.apis.op-palvelut.fi/oauth/v1/token \
-H "Accept:application/json" \
-H "Content-Type:application/x-www-form-urlencoded" \
-H "Cache-Control:no-cache" \
-d "grant_type=refresh_token&refresh_token=********&client_id=********&client_secret=********"

Errors during token retrieval

Errors encountered with token and refresh requests return appropriate error codes with an error description in the response body. For example, attempting to reuse an authorization token will result in a 404 with the following body:

{
    "error": "invalid_code"
}

In general, errors will adhere to the recommendations of the OIDC spec.

5. Call the API with access token

To use the access token and request resources with it from an API, supply the token in the Authorization header. The value of the header must be Bearer <access_token>. See cURL example below for a demonstration.

Make sure you fulfill any other criteria for access set by the API product.

Calling Accounts API with cURL

curl -X GET https://sandbox.apis.op-palvelut.fi/accounts/v3/accounts
-H 'Authorization: Bearer **********
-H 'x-api-key: ************'
-H 'Accept: application/json'
-H 'Content-Type: application/hal+json'

In addition to supplying the access token and API key, please ensure that you fulfill any additional requirements set by the API you intend to use.

6. ID Token

In the case of successful token requests, the authentication and authorization service includes an ID token in the response. The ID Token is a JWT which contains information about the authenticated user and the authentication itself. The ID Token is signed, and contains the following payload structure:

{
  "aud": "example-client",
  "sub": "WccaKnRNVdEU6UgnaKOoYQ7gn84vhh2M3RN19zgy3g8",
  "iss": "http://localhost:8083/oauth",
  "exp": 1544356462,
  "iat": 1541764462
}
FieldTypeExplanation
audstringIntended audience of the ID token. This is the Client ID of your application.
substringA unique ID for the end user that the token describes.
issstringIssuer of the token. This contains the OIDC domain of the TPP application.
exptimestampTimestamp representing the time of expiry of the ID token.
iatstringTimestamp representing the time the ID token was issued.