# Generation Of Client Assertion

{% hint style="info" %}
If you are using a [certified OIDC Relying Party library](https://openid.net/developers/certified-openid-connect-implementations/), the generation of client assertion will be handled by the library, as long as you specify that the `private_key_jwt` method is used for authentication.
{% endhint %}

## Overview

When your backend calls our APIs, you will need to generate a client assertion to authenticate yourself. The generation of this client assertion should be done using the `private_key_jwt` mechanism specified in the [OIDC specifications](https://openid.net/specs/openid-connect-core-1_0-final.html#ClientAuthentication). This mechanism involves you building a client assertion by signing a JWT using one of your signing keys defined in your [JWKS](/docs/technical-specifications/technical-concepts/json-web-key-sets-jwks.md).

Client assertions need to be sent in the [Pushed Authorization Request](https://docs.developer.singpass.gov.sg/docs/technical-specifications/technical-concepts/pages/wD2EDNbwA7OcSQ788qVw#id-1.-sending-the-pushed-authorization-request) and the [Token Request](/docs/technical-specifications/integration-guide/3.-token-exchange.md).

## Generation of JWT

To reduce complexity, we recommend that you use a JWT library to perform the JWT encoding and signing on your behalf, instead of implementing this on your own. You may refer to [this list](https://www.jwt.io/libraries?support=sign\&algorithm=es256) to look for a suitable library for your programming language. To learn more about JWTs and their structure, you may read [this article](https://www.jwt.io/introduction).

The JWT must have the structure outlined below.

### JWT Header

The JWT header should contain the following parameters:

<table><thead><tr><th width="122.17578125">Parameter</th><th>Description</th><th>Data Type</th></tr></thead><tbody><tr><td><code>alg</code></td><td>The signature algorithm that you are using to sign this JWT</td><td><p>One of the following strings:</p><ul><li><code>ES256</code></li><li><code>ES384</code></li><li><code>ES512</code></li></ul></td></tr><tr><td><code>typ</code></td><td>The type of this JWT</td><td>Must be the string <code>JWT</code></td></tr><tr><td><code>kid</code></td><td>The <code>kid</code> of the signing key that you are using to sign this JWT header.<br><br>If this is not provided, we will test against all of the signing keys in your JWKS when attempting to verify the signature.</td><td>String, optional</td></tr></tbody></table>

<details>

<summary>Sample JWT header in JSON form</summary>

```json
{
  "typ": "JWT",
  "alg": "ES256",
  "kid": "my_key_id_01"
}
```

</details>

### JWT Payload

The JWT payload should contain the following claims:

<table><thead><tr><th width="88.7265625">Claim</th><th width="440.61328125">Description</th><th>Data type</th></tr></thead><tbody><tr><td><code>sub</code></td><td>The client ID of your registered client, provided by Singpass during app onboarding.</td><td>A 32-character case-sensitive alphanumeric string.</td></tr><tr><td><code>aud</code></td><td>This should be the issuer identifier of our authorization server. You can obtain this value from the <code>issuer</code> field in the OpenID configuration of our authorization server.</td><td>String</td></tr><tr><td><code>iss</code></td><td>The client ID of your registered client, provided by Singpass during app onboarding.</td><td>A 32-character case-sensitive alphanumeric string.</td></tr><tr><td><code>iat</code></td><td>The unix timestamp, in seconds, at which you generated this JWT.</td><td>Number</td></tr><tr><td><code>exp</code></td><td>The unix timestamp, in seconds, on or after which this JWT <strong>must not</strong> be accepted by us for processing.<br><br>Note also that this must be less than or equal to 2 minutes after <code>iat</code>.</td><td>Number</td></tr><tr><td><code>jti</code></td><td>A unique identifier for this token. This identifier must only be used once. You should generate a new <code>jti</code> value for every request</td><td>String</td></tr></tbody></table>

<details>

<summary>Sample JWT Payload in JSON form</summary>

```json
{
  "sub": "T5sM5a53Yaw3URyDEv2y9129CbElCN2F",
  "aud": "https://id.singpass.gov.sg/fapi",
  "iss": "T5sM5a53Yaw3URyDEv2y9129CbElCN2F",
  "iat": "1756785377",
  "exp": "1756785493",
  "jti": "59e05e3c-9418-4e63-8119-a05157219b74"
}
```

</details>

### Overall JWT (Signed and Encoded)

The JWT should be signed using your private key to form a JSON Web Signature (JWS) in compact serialisation format. This is a format where the three parts of the JWS (the header, the payload, and the signature), are base64url encoded and concatenated together, using a dot (`.`) as the separator.

You must publish the public key corresponding to the private key you used to sign this JWT in your [JWKS](/docs/technical-specifications/technical-concepts/json-web-key-sets-jwks.md).

<details>

<summary>Sample Signed JWT (in Compact Serialisation Format)</summary>

{% code overflow="wrap" %}

```
eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6Im15X2tleV9pZF8wMSJ9.eyJzdWIiOiJUNXNNNWE1M1lhdzNVUnlERXYyeTkxMjlDYkVsQ04yRiIsImF1ZCI6Imh0dHBzOi8vaWQuc2luZ3Bhc3MuZ292LnNnL2ZhcGkiLCJpc3MiOiJUNXNNNWE1M1lhdzNVUnlERXYyeTkxMjlDYkVsQ04yRiIsImlhdCI6IjE3NTY3ODUzNzciLCJleHAiOiIxNzU2Nzg1NDkzIiwiY29kZSI6IlhjeXpsU2VYMWhJeUpGbHN0eHNTRl9VZVhDNUR0aVlrRmdKOFZWeDUybWcifQ.fQMHTVNeCsa_mK6pmfjfi0rxERxDtu6eiMFkkpFdQrirc3u9LxP1_-E_7yIalIhmot1NdBQxbA9s_VztlQUhTQ
```

{% endcode %}

</details>

### Validate Your Client Assertion&#x20;

&#x20;You can validate your Client Assertion using this online validator tool:

[DPoP & Client Assertion Validator](https://client-assertion-dpop-validator.vercel.app/)

This tool helps you:

* Verify JWT structure and compact format
* Check required header parameters (alg, typ, jwk)
* Validate required payload claims
* Confirm signature validity
* Detect common implementation errors


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.developer.singpass.gov.sg/docs/technical-specifications/technical-concepts/generation-of-client-assertion.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
