# Work with JSON Web Signatures

This short guide shows how to create a [JSON Web Signature](https://datatracker.ietf.org/doc/html/rfc7515) (JWS) when working with our [Open Banking API](/docs/api/open-banking). 

JSON Web Signatures (JWSs) are required in several steps when working with all the [Payment initiation endpoints](/docs/api/open-banking).
They are used to validate authenticity and integrity of the content of an API request or response.

JWSs are similar to [JSON Web Tokens (JWTs)](/docs/guides/build-banking-apps/tutorials/work-with-json-web-tokens), as they both consist of a [header](#header), a [payload](#payload) and a cryptographic [signature](#signature), separated by a dot (`.`).

The JWSs in Open Banking are a special case, because the payload section is omitted. 
This is because it is already present in the payload of the API request or response.

## Prerequisites

To work with JWSs, 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 JWS library to cryptographically create a JSON Web Signature

:::tip [Verify your JWK]
[Verify](/docs/guides/build-banking-apps/register-your-application-using-dcr/get-the-jwks-url#verify-that-your-jwks-url-is-publicly-accessible) that your JWKs URL is publicly accessible, and that the content is properly encoded.
:::

To learn how to obtain them for testing purposes, see [Get Started: Prepare your Sandbox environment](/docs/guides/build-banking-apps/get-started/prepare-sandbox-environment).

:::warning
Your JWK **must** contain the `x5c` parameter populated with the signing certificate corresponding to the `kid` you will be using. 

If you fail to include it, we won't be able to validate your JWS.
:::

## Header

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

You must provide the `kid` parameter of your signing certificate and the root domain of the URL where your JWK is hosted.

| Field                             | Description                                                         |
| --------------------------------- | ------------------------------------------------------------------- |
| `typ`                             | Type, always `JOSE` (JSON Object Signing and Encryption)            |
| `alg`                             | Algorithm used for signature, always `PS256`                        |
| `kid`                             | The `kid` parameter of your signing key/certificate                 |
| `crit`                            | Critical parameters, must include `http://openbanking.org.uk/tan`   |
| `http://openbanking.org.uk/tan`   | The root domain of your JWKs URL                                    |

- ![Template]

  This is a template JWS header that you can copy and fill with your own `kid` value and JWKs URL root domain:

  ```json
  {
      "typ": "JOSE",
      "alg": "PS256",
      "kid": "<kid parameter of your signing certificate>",
      "crit": ["http://openbanking.org.uk/tan"],
      "http://openbanking.org.uk/tan": "<root domain of your JWKs URL>"
  }
  ```

- ![Example]

  This is a sample JWS header:

  ```json
  {
      "typ": "JOSE",
      "alg": "PS256",
      "kid": "abc123",
      "crit": ["http://openbanking.org.uk/tan"],
      "http://openbanking.org.uk/tan": "example.com"
  }
  ```

## Payload

In the case of JWS, the payload will be the JSON payload of the API request.

For demonstration purposes, in this guide we are using this sample JSON payload:

```json
{
  "test": "payload"
}
```

:::warning [The signature in a JWS is unique for the provided header and payload.]
Since the payload is provided separately in the request body, you must make sure that its formatting is exactly the same as of the content that was signed. 

This is especially important because signing libraries can remove whitespaces and line breaks from the payload before signing, and thus alter the formatting.
:::

## 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](https://github.com/kjur/jsrsasign) can be used.

```javascript
private_key = "---abc---";

header = {
  "typ": "JOSE",
  "alg": "PS256",
  "kid": "abc123",
  "crit": ["http://openbanking.org.uk/tan"],
  "http://openbanking.org.uk/tan": "example.com"
};

payload = {
  "test": "payload"
};

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

## Full Request with JWS

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

`ewogICJ0eXAiOiAiSk9TRSIsCiAgImFsZyI6ICJQUzI1NiIsCiAgImtpZCI6ICJhYmMxMjMiLAogICJjcml0IjogWyJodHRwOi8vb3BlbmJhbmtpbmcub3JnLnVrL3RhbiJdLAogICJodHRwOi8vb3BlbmJhbmtpbmcub3JnLnVrL3RhbiI6ICJleGFtcGxlLmNvbSIKfQ.**ewogICJ0ZXN0IjogInBheWxvYWQiCn0**.M-tx9BIPmHO8_VpGVmO3yDq--------dFtS6VgiM1kmQuK6E_3S8tKh2BKV_W69Q`

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

:::tip
At this stage you can inspect what exactly is being signed. If you take the payload section (`ewogICJ0ZXN0IjogInBheWxvYWQiCn0`) and base64-decode it into a string, you will get the payload. Check that it matches exactly the payload in your API request.
:::

To avoid sending redundant data, the payload is then removed from the JWS, leaving only the header and signature with an empty payload section:

```ewogICJ0eXAiOiAiSk9TRSIsCiAgImFsZyI6ICJQUzI1NiIsCiAgImtpZCI6ICJhYmMxMjMiLAogICJjcml0IjogWyJodHRwOi8vb3BlbmJhbmtpbmcub3JnLnVrL3RhbiJdLAogICJodHRwOi8vb3BlbmJhbmtpbmcub3JnLnVrL3RhbiI6ICJleGFtcGxlLmNvbSIKfQ..M-tx9BIPmHO8_VpGVmO3yDq--------dFtS6VgiM1kmQuK6E_3S8tKh2BKV_W69Q```

For Open Banking API requests that require a JSON Web signature, this string must be included in the `x-jws-signature` header, as in the example below:

:::note
For the signature section of the JWS, we have used an arbitrary string here.
:::

- ![Production]

  ```shell {6}
  curl --location 'https://oba-auth.revolut.com/domestic-payments' \
  --header 'x-fapi-financial-id: 001580000103UAvAAM' \
  --header 'Authorization: Bearer oa_prod_pwDmU5mA2QOFvxcWszVP06uhI2nIcOAsgC4iuwlzTiw' \
  --header 'Content-Type: application/json' \
  --header 'x-jws-signature: ewogICJ0eXAiOiAiSk9TRSIsCiAgImFsZyI6ICJQUzI1NiIsCiAgImtpZCI6ICJhYmMxMjMiLAogICJjcml0IjogWyJodHRwOi8vb3BlbmJhbmtpbmcub3JnLnVrL3RhbiJdLAogICJodHRwOi8vb3BlbmJhbmtpbmcub3JnLnVrL3RhbiI6ICJleGFtcGxlLmNvbSIKfQ..M-tx9BIPmHO8_VpGVmO3yDq--------dFtS6VgiM1kmQuK6E_3S8tKh2BKV_W69Q' \
  --header 'x-idempotency-key: 048d46a1-f381-4f2b-a79e-a43ee7d1ff90' \
  --data '{
    "test": "payload"
  }'
  ```

- ![Sandbox]

  ```shell
  curl --location 'https://sandbox-oba-auth.revolut.com/domestic-payments' \
  --header 'x-fapi-financial-id: 001580000103UAvAAM' \
  --header 'Authorization: Bearer oa_sand_cWszVP06uhvx4iuwlzTiwI2nIcOAsgCpwDmU5mA2QOF' \
  --header 'Content-Type: application/json' \
  --header 'x-jws-signature: ewogICJ0eXAiOiAiSk9TRSIsCiAgImFsZyI6ICJQUzI1NiIsCiAgImtpZCI6ICJhYmMxMjMiLAogICJjcml0IjogWyJodHRwOi8vb3BlbmJhbmtpbmcub3JnLnVrL3RhbiJdLAogICJodHRwOi8vb3BlbmJhbmtpbmcub3JnLnVrL3RhbiI6ICJleGFtcGxlLmNvbSIKfQ..M-tx9BIPmHO8_VpGVmO3yDq--------dFtS6VgiM1kmQuK6E_3S8tKh2BKV_W69Q' \
  --header 'x-idempotency-key: 048d46a1-f381-4f2b-a79e-a43ee7d1ff90' \
  --data '{
    "test": "payload"
  }'
  ```

## What's next
- [Initiate your first payment](/docs/guides/build-banking-apps/tutorials/initiate-your-first-payment)
- [Test getting a payment consent with Postman](/docs/guides/build-banking-apps/tutorials/test-with-postman/get-a-payment-consent)
- See the API reference for [Domestic payments](/docs/api/open-banking)