Skip to content

JSON Web Signature (JWS) ​

JSON Web Signature (JWS) is a JOSE specification that defines a compact, URL-safe way to represent digitally signed content. Implementing JWS ensures the sender's identity is verified and the message has not been altered, providing non-repudiation for your interactions with the Bahn API.

Here is a summary of how the signing process works:

  1. Generate a P-256 key pair and provide the public key to Bahn during onboarding.
  2. Bahn registers the public key for use by the API.
  3. Once registered, you can call JWS-enabled endpoints with signed request bodies.
  4. Bahn verifies the signature using your registered public key and performs additional checks, including the validity of the url header.

Providing Public Keys ​

Public keys must be submitted to Bahn during onboarding. See Authentication for the full requirements, including mandatory JWK fields.

Workflow ​

The following is a step-by-step guide to manually construct and send a JWS-signed request.

1. Construct the Header and Payload ​

Prepare the request body according to the API reference, then construct the JWS header with the required fields. The url field is mandatory — Bahn uses it to confirm the request has not been replayed against a different endpoint.

Header

json
{
  "alg": "ES256",
  "iat": 1773220702,
  "kid": "client_key",
  "typ": "jose+json",
  "url": "/bn/api/playground/concat-strings"
}

Payload

json
{
  "string1": "Hello",
  "string2": "World"
}

2. Sign with Your Private Key ​

Base64url-encode the header and payload, then sign them using your P-256 private key. Use an established JOSE library to avoid encoding or signing errors.

The resulting compact JWS has three dot-separated parts:

<base64url(header)>.<base64url(payload)>.<signature>

Example

eyJhbGciOiJFUzI1NiIsImlhdCI6MTc3MzIyMDcwMiwia2lkIjoiY2xpZW50X2tleSIsInR5cCI6IkpXUyIsInVybCI6Ii9ibi9hcGkvcGxheWdyb3VuZC9jb25jYXQtc3RyaW5ncyJ9.eyJzdHJpbmcxIjoiSGVsbG8iLCAic3RyaW5nMiI6IldvcmxkIn0.xIY9EZMJTcawCnH7J2NLZO6P66hFfexNU-gJdNqEAuRyHs4szMZLjW--GZ15N_6Q8WYmhY8DX_XVpBySvUigVA

3. Submit the Request ​

Bahn supports two content types for submitting signed requests. Choose whichever best fits your integration.

Option A: Compact Serialization — application/jose ​

Send the JWS compact serialization (header.payload.signature) directly as the request body as a plaintext string:

bash
curl -X POST 'https://t.cakedigibank.tech/bn/api/playground/concat-strings' \
     -H 'Bn-Api-Key: <your-api-key>' \
     -H 'Bn-Jose-Method: jws' \
     -H 'Content-Type: application/jose' \
     -d 'eyJhbGciOiJFUzI1NiIsImlhdCI6MTc3MzIyMDcwMiwia2lkIjoiY2xpZW50X2tleSIsInR5cCI6Impvc2UranNvbiIsInVybCI6Ii9ibi9hcGkvcGxheWdyb3VuZC9jb25jYXQtc3RyaW5ncyJ9.eyJzdHJpbmcxIjoiSGVsbG8iLCAic3RyaW5nMiI6IldvcmxkIn0.xIY9EZMJTcawCnH7J2NLZO6P66hFfexNU-gJdNqEAuRyHs4szMZLjW--GZ15N_6Q8WYmhY8DX_XVpBySvUigVA'

Structure:

BASE64URL(header) . BASE64URL(payload) . BASE64URL(signature)

Option B: JSON Serialization — application/jose+json ​

Send the JWS General JSON Serialization (RFC 7515 Section 7.2) as the request body. This format separates the protected header, payload, and signature into distinct JSON fields:

bash
curl -X POST 'https://t.cakedigibank.tech/bn/api/playground/concat-strings' \
     -H 'Bn-Api-Key: <your-api-key>' \
     -H 'Bn-Jose-Method: jws' \
     -H 'Content-Type: application/jose+json' \
     -d '{
       "payload": "eyJzdHJpbmcxIjoiSGVsbG8iLCAic3RyaW5nMiI6IldvcmxkIn0",
       "signatures": [
         {
           "protected": "eyJhbGciOiJFUzI1NiIsImlhdCI6MTc3MzIyMDcwMiwia2lkIjoiY2xpZW50X2tleSIsInR5cCI6Impvc2UranNvbiIsInVybCI6Ii9ibi9hcGkvcGxheWdyb3VuZC9jb25jYXQtc3RyaW5ncyJ9",
           "signature": "xIY9EZMJTcawCnH7J2NLZO6P66hFfexNU-gJdNqEAuRyHs4szMZLjW--GZ15N_6Q8WYmhY8DX_XVpBySvUigVA"
         }
       ]
     }'

Structure:

json
{
  "payload": "<base64url(payload)>",
  "signatures": [
    {
      "protected": "<base64url(header)>",
      "signature": "<base64url(signature)>"
    }
  ]
}

When using application/jose+json with multiple signatures, Bahn uses the first signature entry for verification.

On success, Bahn returns the concatenated result:

json
{
  "result": "HelloWorld"
}

Developers