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).
To work with JWT, you must first prepare:
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.
Field | Description |
---|---|
alg | Algorithm used for signature, always PS256 |
kid | The 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>"
}
In the case of JWT, the payload will contain a JSON object with information about the consent.
Field | Description | Required |
---|---|---|
response_type | Always set to code id_token . | yes |
client_id | The client ID for your application. | yes |
aud | The intended audience for the JWT. This must contain https://oba-auth.revolut.com or https://sandbox-oba-auth.revolut.com for Sandbox. | yes* |
redirect_uri | One of the redirect URIs that you defined when you created the application. | yes |
scope | The scope that you are requesting, for example, accounts or payments . | yes |
state | OAuth parameter that lets you restore the state of the session after redirection. If provided, this value is returned in the redirect URI. | no |
nbf | A Unix timestamp, in seconds, before which the JWT is not valid. This value cannot be more than 60 minutes in the past. | yes* |
exp | A 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* |
claims | In its id_token.openbanking_intent_id.value field, it must contain the ID of the consent which will be approved by the user. | yes |
*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.
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"
}
}
}
}
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);
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.
For the signature section of the JWT, we have used an arbitrary string.