Setup Client Assertion

A Client Assertion is a JWT directly produced by a client application using a cryptographic key and is presented as proof of the client's identity. Client Assertions provide a strong method of authenticating clients before returning an access_token for them to access the data.

Relying Party (RP) is required to present an assertion JWT in the request body when calling the token endpoint. Singpass will then verify this JWT against a JWK provided by the RP in the Application configuration.

RP is required to generate an assertion JWT that has the following header and claims, and is signed with the JWK indicated in the Application configuration.

Step 1: Define Client Assertion

The JWK Header should have the following attributes:

Example of JWT Header

{
  "typ": "JWT",
  "alg": "ES256",
  "kid": "sig-2024"
}

The JWK Claims should have the following attributes:

KeyDescription

sub

This should be client_id of the registered client provided in the Application configuration for each Application

aud

The recipient that the JWT is intended for. This must match the issuer field in the response endpoint Example: https://id.singpass.gov.sg

iss

This should be client_id of the registered client provided in the Application configuration for each Application

iat

The time at which the JWT was issued. Ref

exp

The expiration time on or after which the JWT MUST NOT be accepted by NDI for processing. Additionally, NDI will not accept tokens with an exp longer than 2 minutes since iat. Ref

code

(Optional) This should be the auth code which is used to exchange for an ID token. It should be identical to the code form param sent outside the client_assertion. This enables increased security by signing the code so that the client_assertion can only be used once for a specific request.

Example of JWT Claims

{
  "sub": "alh5DS2Gfndv9i0jXYViqGIhiQdP4+4BrUvBhDXBYKk=",
  "aud": "https://stg-id.singpass.gov.sg",
  "iss": "alh5DS2Gfndv9i0jXYViqGIhiQdP4+4BrUvBhDXBYKk=",
  "iat": 1609907375,
  "exp": 1609907975
}

The JWK Signature

The JWT assertion signature is a crucial component. RP to ensure the JWT assertion is signed with the JWK private key to the public keys provided by the RP in the Application configuration.

Example of JWT Client Assertion

{
  "typ": "JWT",
  "alg": "ES256",
  "kid": "testing123"
},
{
  "sub": "alh5DS2Gfndv9i0jXYViqGIhiQdP4+4BrUvBhDXBYKk=",
  "aud": "https://stg-id.singpass.gov.sg",
  "iss": "alh5DS2Gfndv9i0jXYViqGIhiQdP4+4BrUvBhDXBYKk=",
  "iat": 1609907375,
  "exp": 1609907975
},
[Signature]

Step 2: Add the Client Assertion function to the Application

Here is a sample code that can be referenced as a function to generate client assertion.

JOSE is a simple package that can be used for JSON Object Signing and Encryption

  • Create a new function file in your application called generateClientAssertion.js.

  • Install the JOSE (JSON Object Signing and Encryption) package which will be used to generate and sign the client assertion. Open the terminal, use npm install jose to install the package.

npm install jose
  • Copy the following code into the generateClientAssertion.js file. Update the signature keys, JWT claims value, and the key ID as explained above.

//generateClientAssertion.js

const alg = "ES256";
//Signature Private Keys JWT
const jwk = 
{
      kty: "EC",
      d: "0GlHbGc8vSnyiB-Lf4_im_WFwrxM0MJjkk96o1-K3JQ",
      crv: "P-256",
      x: "wg11s6ZpBc0my5gT-mYatTZRDhgStyd_0qARVBwAWa4",
      y: "hlVoYWwlCuTMnm79Ppmf3RslIwDRhqdCCnm01PkhA2s",
};


const privateKey = await jose.importJWK(jwk, alg);
const nowTime = moment().unix();
const futureTime = moment().add(2, "minutes").unix();
const jwt = await new jose.SignJWT({
      sub: "tLRDBkf1CNy5Rsi34mEKuOD5EpQAwjIq", //Update Client ID
      iss: "tLRDBkf1CNy5Rsi34mEKuOD5EpQAwjIq", //Update Client ID
      aud: "https://stg-id.singpass.gov.sg", 
      iat: nowTime,
      exp: futureTime,
    })
      .setProtectedHeader({
        alg: "ES256",
        kid: "sig-2024", //Update KeyID from the Signature JWT
        typ: "JWT",
      })
      .sign(privateKey);

console.log(jwt);
  • Run the function. Below is the sample client assertion output of the console.log.

eyJraWQiOiJycF9rZXlfMDEiLCJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCJ9.eyJzdWIiOiIwamVYZ2dMd3JFelNDcGRmdHpzNmlHbXdZbWNMS3F4TiIsImF1ZCI6Imh0dHBzOi8vc3RnLWlkLnNpbmdwYXNzLmdvdi5zZyIsImNvZGUiOiJuMGVzYzNOUnplN0xUQ3U3aVl6UzZhNWFjYzNmMG9ncDQiLCJpc3MiOiJodHRwOi8vZXhhbXBsZS5jb20iLCJleHAiOjE3MTQ5ODMzNDcsImlhdCI6MTcxNDk4MzIyN30.AAAAAAAAAAAAAAAAAAAAAO_3oh85dPCvrYpZhH8DyQW97csQhrgqwzmXTb6XU2S0AAAAAAAAAAAAAAAAAAAAAHkNRM-g9kT1bwPMYQsJ6lU9Drn-_Zcjht5pbR_FF0f_

JWT.IO is an example of an online client assertion verifier. This can be a useful tool to verify if the client assertion generated is valid.

If you passed the verification, your client assertion is ready to be used for the later steps.

Next steps