Authorization Code Grant

Client Authentication - Client Assertion JWT

Assertion JWT Structure

The RP is required to generate an assertion JWT that has the following header and claims, and is signed with the JWK that was provided during onboarding.

JWT Header

The header must include alg and typ.

The supported alg types are:

  • ES256

  • ES384

  • ES512.

This must match the alg value in the signing key used to sign the assertion (if the signing JWK specifies alg explicitly).

The header should also include kid of the signing key to help identify which of the RP’s signing keys was used, though this is not mandatory. If omitted, we will test against all known signing keys when attempting to verify the signature.

example

{
  "typ" : "JWT",
  "alg" : "ES256",
  "kid" : "rp_key_01"
}

JWT Claims

Request / Response Structure

Curl request

$ curl 'https://stg-id.singpass.gov.sg/token' -i -X POST \
    -H 'Content-Type: application/x-www-form-urlencoded; charset=ISO-8859-1' \
    -d 'grant_type=authorization_code&redirect_uri=http%3A%2F%2Fexample.com&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=eyJraWQiOiJycF9rZXlfMDEiLCJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCJ9.eyJzdWIiOiJnblk2RXJpY2hwYjV0NE5GUlA5UjRMN2FFQzlOMEZRSCIsImF1ZCI6Imh0dHBzOi8vc3RnLWlkLnNpbmdwYXNzLmdvdi5zZyIsImNvZGUiOiJuMGVzYzNOUnplN0xUQ3U3aVl6UzZhNWFjYzNmMG9ncDQiLCJpc3MiOiJodHRwOi8vZXhhbXBsZS5jb20iLCJleHAiOjE3MjczMjIwNjUsImlhdCI6MTcyNzMyMTk0NX0.AAAAAAAAAAAAAAAAAAAAAIvHG8uapa4w10pPn_S_7uyYPXNJWU7389sTLNHXrCKhAAAAAAAAAAAAAAAAAAAAAIxyKbbZfLSkduU6WIPrrPe1kGvmHmzXL4PHpgAJ0g0d&code=n0esc3NRze7LTCu7iYzS6a5acc3f0ogp4&client_id=gnY6Erichpb5t4NFRP9R4L7aEC9N0FQH&code_verifier=mN7szCmmIc6Z2Vg-iaX7f7RDVsKAhY5GG-r7Crq0jxTdxY0xyPKnsAEWtEMdZ3D8QW5rs-C824W3Jwntcw'

Form parameters

HTTP request

POST /token HTTP/1.1
Content-Type: application/x-www-form-urlencoded; charset=ISO-8859-1
Host: stg-id.singpass.gov.sg
Content-Length: 788

grant_type=authorization_code&redirect_uri=http%3A%2F%2Fexample.com&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=eyJraWQiOiJycF9rZXlfMDEiLCJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCJ9.eyJzdWIiOiJnblk2RXJpY2hwYjV0NE5GUlA5UjRMN2FFQzlOMEZRSCIsImF1ZCI6Imh0dHBzOi8vc3RnLWlkLnNpbmdwYXNzLmdvdi5zZyIsImNvZGUiOiJuMGVzYzNOUnplN0xUQ3U3aVl6UzZhNWFjYzNmMG9ncDQiLCJpc3MiOiJodHRwOi8vZXhhbXBsZS5jb20iLCJleHAiOjE3MjczMjIwNjUsImlhdCI6MTcyNzMyMTk0NX0.AAAAAAAAAAAAAAAAAAAAAIvHG8uapa4w10pPn_S_7uyYPXNJWU7389sTLNHXrCKhAAAAAAAAAAAAAAAAAAAAAIxyKbbZfLSkduU6WIPrrPe1kGvmHmzXL4PHpgAJ0g0d&code=n0esc3NRze7LTCu7iYzS6a5acc3f0ogp4&client_id=gnY6Erichpb5t4NFRP9R4L7aEC9N0FQH&code_verifier=mN7szCmmIc6Z2Vg-iaX7f7RDVsKAhY5GG-r7Crq0jxTdxY0xyPKnsAEWtEMdZ3D8QW5rs-C824W3Jwntcw

HTTP response

HTTP/1.1 200 OK
Cache-Control: no-cache, no-store, must-revalidate
x-ndi-response-category: client-assertion-auth-code
X-XSS-Protection: 0
X-Frame-Options: DENY
Date: Thu, 26 Sep 2024 03:39:05 GMT
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
Transfer-Encoding: chunked
Content-Type: application/json
Content-Length: 597

{
  "access_token" : "Ul5JqK8vJX8Jfgo7UjpiIigF7DciW7YGnUACLN1/T80=",
  "token_type" : "Bearer",
  "id_token" : "eyJraWQiOiJuZGlfc3RnXzAxIiwidHlwIjoiSldUIiwiYWxnIjoiRVMyNTYifQ.eyJhdWQiOiJnblk2RXJpY2hwYjV0NE5GUlA5UjRMN2FFQzlOMEZRSCIsInN1YiI6InM9Uzg4MjkzMTRCLHU9MWMwY2VlMzgtM2E4Zi00ZjhhLTgzYmMtN2EwZTRjNTlkNmE5IiwiYW1yIjpbInB3ZCIsInN3ayJdLCJpc3MiOiJodHRwczovL3N0Zy1pZC5zaW5ncGFzcy5nb3Yuc2ciLCJleHAiOjE3MjczMjI1NDUsImlhdCI6MTcyNzMyMTk0NSwibm9uY2UiOiJMNW5tUWZjZXREREllaW5jb3F2Q3JGeUd2K25Ib2JrdjRYb2NOWVBDWGFRPSJ9.bD1osnkuL-hXCXY9L_LbveANix_tBsjk8872bL04tTPFGMkzMjE85W8fTwQXrPSFnwQtgzmLB2__i0vdGYnfgA"
}

Request body

grant_type=authorization_code&redirect_uri=http%3A%2F%2Fexample.com&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=eyJraWQiOiJycF9rZXlfMDEiLCJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCJ9.eyJzdWIiOiJnblk2RXJpY2hwYjV0NE5GUlA5UjRMN2FFQzlOMEZRSCIsImF1ZCI6Imh0dHBzOi8vc3RnLWlkLnNpbmdwYXNzLmdvdi5zZyIsImNvZGUiOiJuMGVzYzNOUnplN0xUQ3U3aVl6UzZhNWFjYzNmMG9ncDQiLCJpc3MiOiJodHRwOi8vZXhhbXBsZS5jb20iLCJleHAiOjE3MjczMjIwNjUsImlhdCI6MTcyNzMyMTk0NX0.AAAAAAAAAAAAAAAAAAAAAIvHG8uapa4w10pPn_S_7uyYPXNJWU7389sTLNHXrCKhAAAAAAAAAAAAAAAAAAAAAIxyKbbZfLSkduU6WIPrrPe1kGvmHmzXL4PHpgAJ0g0d&code=n0esc3NRze7LTCu7iYzS6a5acc3f0ogp4&client_id=gnY6Erichpb5t4NFRP9R4L7aEC9N0FQH&code_verifier=mN7szCmmIc6Z2Vg-iaX7f7RDVsKAhY5GG-r7Crq0jxTdxY0xyPKnsAEWtEMdZ3D8QW5rs-C824W3Jwntcw

Response body

{
  "access_token" : "Ul5JqK8vJX8Jfgo7UjpiIigF7DciW7YGnUACLN1/T80=",
  "token_type" : "Bearer",
  "id_token" : "eyJraWQiOiJuZGlfc3RnXzAxIiwidHlwIjoiSldUIiwiYWxnIjoiRVMyNTYifQ.eyJhdWQiOiJnblk2RXJpY2hwYjV0NE5GUlA5UjRMN2FFQzlOMEZRSCIsInN1YiI6InM9Uzg4MjkzMTRCLHU9MWMwY2VlMzgtM2E4Zi00ZjhhLTgzYmMtN2EwZTRjNTlkNmE5IiwiYW1yIjpbInB3ZCIsInN3ayJdLCJpc3MiOiJodHRwczovL3N0Zy1pZC5zaW5ncGFzcy5nb3Yuc2ciLCJleHAiOjE3MjczMjI1NDUsImlhdCI6MTcyNzMyMTk0NSwibm9uY2UiOiJMNW5tUWZjZXREREllaW5jb3F2Q3JGeUd2K25Ib2JrdjRYb2NOWVBDWGFRPSJ9.bD1osnkuL-hXCXY9L_LbveANix_tBsjk8872bL04tTPFGMkzMjE85W8fTwQXrPSFnwQtgzmLB2__i0vdGYnfgA"
}

Response fields

Error Response

Singpass generally follows OIDC error response specifications. For more information, please refer to Token Error Response specifications.

ID Token Structure

The format and structure of the issued ID Token will vary depending on the client’s profile as specified in this table below:

Overview of a JWS in JWE

An encrypted ID token will returned from the /token endpoint is a JWS in JWE that is in compact serialization form. It has the following structure:

  • JWE Header

  • Encrypted Key

  • Initialization Vector

  • Encrypted Payload (if decrypted, this would be the Base64 encoded form of a JWS ID Token)

  • Authentication Tag

See https://datatracker.ietf.org/doc/html/rfc7516#section-3.1 for more details.

JWE Header

The JWE will contain these standard headers. Refer to https://tools.ietf.org/html/rfc7515#section-4 for more information about each header.

Note: Relying parties should use the kid field in the header to determine which key NDI used for encryption.

example

{
	"kid": "client_01",
	"cty": "JWT",
	"enc": "A256CBC-HS512",
	"alg": "ECDH-ES+A256KW"
}

Overview of JWS

The JWS ID token returned from the /token endpoint is in compact serialization form. A JWS has the following structure.

  • JWS Header

  • Payload (containing claims)

  • Signature

JWS Header

The JWS ID token will contain these standard headers. Refer to https://tools.ietf.org/html/rfc7515#section-4 for more information about each header.

example

{
  "kid" : "ndi_stg_01",
  "typ" : "JWT",
  "alg" : "ES256"
}

JWS Claims

The JWS ID token will contain the following claims.

example

{
  "aud" : "gnY6Erichpb5t4NFRP9R4L7aEC9N0FQH",
  "sub" : "s=S8829314B,u=1c0cee38-3a8f-4f8a-83bc-7a0e4c59d6a9",
  "amr" : [ "pwd", "swk" ],
  "iss" : "https://stg-id.singpass.gov.sg",
  "exp" : 1727322545,
  "iat" : 1727321945,
  "nonce" : "L5nmQfcetDDIeincoqvCrFyGv+nHobkv4XocNYPCXaQ="
}

Table 1. Description of Claims

Last updated