JWTJSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted., or JSON Web Token, is an open standard (RFC 7519) method of securely sending information in a JSON object between the TPP and Token. The information transmitted can be verified and trusted because it is digitally signed using a public/private key pair in, for example, an RSAPublic-key cryptosystem for both encryption and authentication. Under RSA, the encryption key is public and it is always different from the decryption key which is kept secret (private). Anyone can use the public key to encrypt a message, but only someone with the private key can decode the message. The RSA acronym is derived from the initial letters of the surnames of Ron Rivest, Adi Shamir, and Leonard Adleman, who first publicly described the algorithm in 1977. or EdDSAEdwards-curve Digital Signature Algorithm – a digital signature scheme using a variant of the Schnorr signature based on twisted Edwards curves. It is designed to be fast without sacrificing security. algorithm.
A JWT is generated to authorise TPP requests after user login and authentication with the bank. Thereafter, whenever you as TPP need to access a protected resource, you send the JWT in the authorisation header using the bearer schemeAn authentication method using security tokens. Bearer authentication is understood to mean: "Give access to the bearer of this token." when making subsequent requests on behalf of the user.
The content of the header takes this form:
Authorization: Bearer <jwt>
Remember, however, that the information contained in signed tokens is exposed, even though it cannot be changed. Hence, never put secret information within the token, and because all JWTs need to be treated as secure credentials, do not keep them longer than necessary.
JWTs can be broken down into three parts: header, payload, and signature. Each part is separated from the other by dot (.), and follows this structure:
The Header describes the algorithm used to generate the signature. A decoded version of a simple header looks like this, wherein ES256Asymmetric key cryptography algorithm combined with elliptic curve digiral signature algorithm (ECDSA) using P-256 and SHA-256. is the SHA-256Hash function computed with eight 32-bit words. hashing algorithm used to generate the signature:
// member ID
// key ID
// HTTP method
// base URL
// only where required
This header JSON is then Base64Url encoded to form the first part of the JWT.
This is the second part of the JWT. It contains the same content as the body of the request, and must be identical to the body of the request in every respect or authentication will fail. Even the position of spaces must be identical. In calls that do not have a body, no body content is required in the JWT; i.e., the payload is empty.
The JWT payload for a simple transfer might look like this:
The payload is Base64Url encoded to form the second part of the token.
The signature part of a JWT is derived from the header and payload fields. You create the signature by combining the base64url encoded representations of the header and payload with a dot (.)
base64UrlEncode(header) + “.” + base64UrlEncode(payload)
Your private key remains unknown to Soldo. Only the public key is shared.
Hence, once you provide your public key to Soldo, a keyId is generated. You'll need to specify this keyId in the Authorization header so we know which key you're using for signing. Any change or modification to this particular JWT thereafter will fail verification.
Those are the basics. Now, let's put it all together.
As discussed above, the Authorization header for a Soldo API request is a JSON string identifying the request and the signing. It contains a JWT header and payload with the following respective parameters.
|JWT Header Parameters|
|alg||Algorithm – case-sensitive string identifying the signing key algorithm (e.g., "RS256" or "EdDSA")|
|exp||Expiration time in milliseconds; ex. 1 minute = 60000(<1 minute from the time of the request is recommended)|
|mid||member id string|
|kid||key id string|
|method||String indicating HTTP method (e.g., GET / POST / PUT / DELETE)|
|host||String identifying the host of your request (e.g., "api.dev.token.io")|
|path||String defining the path of your request (e.g., "/banks/iron/consents")|
|query||Required only if there is a query in your request (e.g., "type=access")|
|JWT Payload Parameters|
|body||This is the requestPayload, populated with all relevant request fields|
Here's a typical example of the token header:
// member ID
// key ID
// HTTP method
// base URL
// only where required
Create the Token
All base64 URLUniform Resource Locator (aka web address) – specifies a location on a computer network and a mechanism for retrieving it. encoding should be without padding in accordance with RFC 7515 Appendix C. Soldo also supports detached JWT in accordance with RFC 7515 Appendix F, which you can leverage to detach payload content from the request header.
// The request body
// JWT payload
// JWT header
String encodedHeader = Base64UrlEncode(header);
String encodedPayload = Base64UrlEncode(body);
String signingInput = encodedHeader + "." + encodedPayload;
String signature = sign(signingInput);
// Detached JWT
Additional Notes: Soldo supports both JWT practices — original and detached.
For detached JWT, the middle part between encodedHeader and signature (e.g., encodedBody) is optional and can be omitted, since it is a duplicate of the request body.
In general, detached JWT can help save bandwidth, especially when the request body is large.
The Authorization header proper contains the "Bearer" schema plus the jwt.
"Bearer " +
Here's an example of the completed Authorization header:
Again, for details on AISAccount Information Service – supports TPP secure access to customer accounts and data, but only with the bank-verified consent of the customer., PISPayment Initiation Service – with the consent of the end-user, initiates a payment from a user-held account upon user authentication., and CAFConfirmation of Available Funds – A CBPII begins the Confirmation of Funds journey by registering a request to confirm funds of a PSU. The CBPII must then obtain consent from the PSU in order to authorise the request, enabling it to request the information. Once the request is authorised, the CBPII will be able to invoke Confirmation of Funds API to the confirm availability of funds in the PSU account. request and response payload structures, see the API's Swagger Specification under the Banks tag.
Heads up: There are some corner cases in which the path in the header contains a character that is not URL-safe. For these cases, Token expects a URL-encoded endpoint but a raw path in the JWT Authorization header.
Here's an example:
curl --location --request GET
Here, it's important to note that the raw transaction ID in the example above is URL-encoded in the path, in accordance with the RESTful standard.
Tip: Copy-paste your desired JWT components — header and payload — into jwt.io Debugger to decode, verify, and generate JWTs.