Guides • Build Banking Apps
Work with JSON Web Tokens
doc

Work with JSON Web Tokens

This short guide shows how to create a JSON Web Token when working with our Open Banking API.

JSON Web Tokens (JWTs) are required when authorising Open Banking consents.

They are composed of a base64url-encoded header, payload and cryptographic signature, separated by a dot ., and as such, are similar to JSON Web Signatures (JWSs).

Prerequisites

To work with JWT, you must first prepare:

  • A signing key and signing certificate pair
  • A JWKs URL at which your JSON Web Key (JWK) is publicly available
  • A JWT library to cryptographically create a JSON Web Token

To learn how to obtain them for testing purposes, see Get Started: Prepare your Sandbox environment.

The header section of the JWT contains mandatory parameters to validate the signature of payment requests.

You must provide the kid parameter of your signing certificate.

FieldDescription
algAlgorithm used for signature, always PS256
kidThe kid parameter of your signing key / certificate

This is a template JWT header that you can copy and fill with your own kid value:

{
"alg": "PS256",
"kid": "<kid parameter of your signing certificate>"
}

Payload

In the case of JWT, the payload will contain a JSON object with information about the consent.

FieldDescriptionRequired
response_typeAlways set to code id_token.yes
client_idThe client ID for your application.yes
audThe intended audience for the JWT. This must contain https://oba-auth.revolut.com or https://sandbox-oba-auth.revolut.com for Sandbox.yes*
redirect_uriOne of the redirect URIs that you defined when you created the application.yes
scopeThe scope that you are requesting, for example, accounts or payments.yes
stateOAuth parameter that lets you restore the state of the session after redirection. If provided, this value is returned in the redirect URI.no
nbfA Unix timestamp, in seconds, before which the JWT is not valid. This value cannot be more than 60 minutes in the past.yes*
expA Unix timestamp, in seconds, after which the JWT is no longer valid. This value must not be more than 60 minutes after the value in nbf.yes*
claimsIn its id_token.openbanking_intent_id.value field, it must contain the ID of the consent which will be approved by the user.yes
Parameters required for FAPI 1 Advanced

*The values for nbf, exp, and aud are currently optional; however, with the introduction of FAPI 1 Advanced, as of 10 July 2025, these values will become required.

Unix timestamp recommendations

In order to accommodate for minor time synchronisation differences, we recommend using an nbf value of 5 minutes into the past, and an exp value which is 55 minutes after nbf.

For demonstration purposes, in this guide we are using the following JSON payload. In this sample payload, the JWT was only valid on 29 Jan 2025, between 13:50:53 and 14:45:53 (UTC).

{
"response_type": "code id_token",
"client_id": "d363951f-0f70-43e9-80e6-db9b0c578061",
"redirect_uri": "https://example.com",
"aud": "https://oba-auth.revolut.com",
"scope": "payments",
"state": "86413c89-a69f-449f-97cc-a6ca949338f6",
"nbf": 1738158653,
"exp": 1738161953,
"claims": {
"id_token": {
"openbanking_intent_id": {
"value": "43e56447-4088-4111-a6e8-1eef585645a7"
}
}
}
}

Signature

To compute the signature, you can use any library that is compatible with your environment.

For example, in JavaScript, a library such as jsrsasign can be used.


private_key = "---abc---";

header = {
"alg": "PS256",
"kid": "abc123"
};

payload = {
"response_type": "code id_token",
"client_id": "d363951f-0f70-43e9-80e6-db9b0c578061",
"redirect_uri": "https://example.com",
"aud": "https://oba-auth.revolut.com",
"scope": "payments",
"state": "86413c89-a69f-449f-97cc-a6ca949338f6",
"nbf": 1738158653,
"exp": 1738161953,
"claims": {
"id_token": {
"openbanking_intent_id": {
"value": "43e56447-4088-4111-a6e8-1eef585645a7"
}
}
}
};

sJWT = KJUR.jws.JWS.sign("PS256", header, payload, private_key);

Full JWT

The final JWT for the above header and payload would result in:

eyJhbGciOiJQUzI1NiIsImtpZCI6ImFiYzEyMyJ9.eyJyZXNwb25zZV90eXBlIjoiY29kZSBpZF90b2tlbiIsImNsaWVudF9pZCI6ImQzNjM5NTFmLTBmNzAtNDNlOS04MGU2LWRiOWIwYzU3ODA2MSIsInJlZGlyZWN0X3VyaSI6Imh0dHBzOi8vZXhhbXBsZS5jb20iLCJhdWQiOiJodHRwczovL29iYS1hdXRoLnJldm9sdXQuY29tIiwic2NvcGUiOiJwYXltZW50cyIsInN0YXRlIjoiODY0MTNjODktYTY5Zi00NDlmLTk3Y2MtYTZjYTk0OTMzOGY2IiwibmJmIjoxNzM4MTU4NjUzLCJleHAiOjE3MzgxNjE5NTMsImNsYWltcyI6eyJpZF90b2tlbiI6eyJvcGVuYmFua2luZ19pbnRlbnRfaWQiOnsidmFsdWUiOiI0M2U1NjQ0Ny00MDg4LTQxMTEtYTZlOC0xZWVmNTg1NjQ1YTcifX19fQ.jVM_DvUkBkN5HVtsG1GyEjC--------shNdHoAphHInCxU72eC4UOfzS4rUoBJDw

The payload section above was bolded to highlight the three sections composing a JWT and facilitate reading.

note

For the signature section of the JWT, we have used an arbitrary string.

What's next

Was this page helpful?