Singpass Developer Docs
CIBA
CIBA
  • Step-up Authentication using Push Notifications
    • Backchannel Authentication Endpoint
    • Token Endpoint
    • .well-known Endpoints
  • Staging and Production Endpoints
  • Error Response
Powered by GitBook
On this page
  • Client-Initiated Backchannel Authentication (CIBA) Grant
  • Client Authentication - Client Assertion JWT
  • Request / Response Structure
  • ID Token Structure
  • Client JWK Requirements
  • JWK for signing
  • JWK for encryption
  • JWKS URL Service Level Expectations

Was this helpful?

  1. Step-up Authentication using Push Notifications

Token Endpoint

PreviousBackchannel Authentication EndpointNext.well-known Endpoints

Last updated 3 months ago

Was this helpful?

Endpoint to obtain an ID token. The ID token is a signed JWT that contains user information in the sub claim, and is signed by Singpass Auth. RPs will be able to verify the ID token’s JWT signature with our JWKS endpoint.

For the Step-up authentication flow, only the following grant(s) is supported:

  • urn:openid:params:grant-type:ciba

In the below sections, we are going to describe the API contract.

Client-Initiated Backchannel Authentication (CIBA) Grant

This grant type allows the RP to obtain an ID token for the user indicated by the login_hint parameter that was provided during initiation. This is only allowed for confidential RPs.

Currently, Singpass only supports Poll mode, which means that RPs need to poll the token endpoint at regular intervals until they receive an ID token or receive certain error codes (see ).

Important

RPs should NOT send two overlapping token requests with the same auth_req_id. RPs should always wait until receiving the response to the previous request before sending out the next request.

Note

It is recommended for RPs to wait for at least 30s for a response before trying again.

Client Authentication - Client Assertion JWT

RPs must authenticate themselves using Client Assertion JWT.

In this authentication mechanism, the RP is required to present an assertion JWT in the request body. Singpass will then verify this JWT against a JWK provided by the RP during onboarding.

This method of authentication relies on PKI and eradicates the need to keep and transfer secrets. You may refer to for more details.

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

Path
Type
Description

sub

String

This should be client_id of the registered client.

aud

String

iss

String

This should be client_id of the registered client.

iat

Number

exp

Number

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 'client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&auth_req_id=9f7e4f01-45cc-4eed-84c2-f7f58233f7fa&client_assertion=eyJraWQiOiJzaWdJZCIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJpc3MiOiJpTUJ3MlhkR2VHanRYRVl4TURoT1RxUnN5a000dHRaZiIsInN1YiI6ImlNQncyWGRHZUdqdFhFWXhNRGhPVHFSc3lrTTR0dFpmIiwiYXVkIjoiaHR0cHM6Ly9zdGctaWQuc2luZ3Bhc3MuZ292LnNnIiwiZXhwIjoxNzM5NDk3MjY4LCJpYXQiOjE3Mzk0OTcxNDh9.8LhU6OSaZhZqJ90T2i6S1ay-Ir_mbw_PXOvjI49BhtR--3A2F3WgLoiNesDHFVCSzz7uv4NoiQqGWxn5C0hdWA&grant_type=urn%3Aopenid%3Aparams%3Agrant-type%3Aciba'

Form parameters

Parameter
Description

auth_req_id

Authentication request id.

grant_type

The type of grant being requested. This must be set to urn:openid:params:grant-type:ciba.

client_assertion_type

This MUST be set to urn:ietf:params:oauth:client-assertion-type:jwt-bearer

client_assertion

A JWT identifying the client.

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: 557

client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&auth_req_id=9f7e4f01-45cc-4eed-84c2-f7f58233f7fa&client_assertion=eyJraWQiOiJzaWdJZCIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJpc3MiOiJpTUJ3MlhkR2VHanRYRVl4TURoT1RxUnN5a000dHRaZiIsInN1YiI6ImlNQncyWGRHZUdqdFhFWXhNRGhPVHFSc3lrTTR0dFpmIiwiYXVkIjoiaHR0cHM6Ly9zdGctaWQuc2luZ3Bhc3MuZ292LnNnIiwiZXhwIjoxNzM5NDk3MjY4LCJpYXQiOjE3Mzk0OTcxNDh9.8LhU6OSaZhZqJ90T2i6S1ay-Ir_mbw_PXOvjI49BhtR--3A2F3WgLoiNesDHFVCSzz7uv4NoiQqGWxn5C0hdWA&grant_type=urn%3Aopenid%3Aparams%3Agrant-type%3Aciba

HTTP response

HTTP/1.1 200 OK
Expires: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
X-XSS-Protection: 0
Pragma: no-cache
X-Frame-Options: DENY
Date: Fri, 14 Feb 2025 01:39:09 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: 446

{"token_type":"Bearer","id_token":"eyJraWQiOiJuZGlfc3RnXzAxIiwidHlwIjoiSldUIiwiYWxnIjoiRVMyNTYifQ.eyJhdWQiOiJpTUJ3MlhkR2VHanRYRVl4TURoT1RxUnN5a000dHRaZiIsInN1YiI6InM9Uzg4MjkzMTRCLHU9MWMwY2VlMzgtM2E4Zi00ZjhhLTgzYmMtN2EwZTRjNTlkNmE5IiwiYW1yIjpbInB3ZCIsInN3ayJdLCJpc3MiOiJodHRwczovL3N0Zy1pZC5zaW5ncGFzcy5nb3Yuc2ciLCJleHAiOjE3Mzk0OTc3NDgsImlhdCI6MTczOTQ5NzE0OH0.BxXLysNFj7TKZBydqXICOCzLzQyylt_Gde18_lSLq4ZcWNz8TY3ZGT_DXU5dWkBEJ4OSaDcEfpxpwNdd-MeEDA"}

Request body

client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&auth_req_id=9f7e4f01-45cc-4eed-84c2-f7f58233f7fa&client_assertion=eyJraWQiOiJzaWdJZCIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJpc3MiOiJpTUJ3MlhkR2VHanRYRVl4TURoT1RxUnN5a000dHRaZiIsInN1YiI6ImlNQncyWGRHZUdqdFhFWXhNRGhPVHFSc3lrTTR0dFpmIiwiYXVkIjoiaHR0cHM6Ly9zdGctaWQuc2luZ3Bhc3MuZ292LnNnIiwiZXhwIjoxNzM5NDk3MjY4LCJpYXQiOjE3Mzk0OTcxNDh9.8LhU6OSaZhZqJ90T2i6S1ay-Ir_mbw_PXOvjI49BhtR--3A2F3WgLoiNesDHFVCSzz7uv4NoiQqGWxn5C0hdWA&grant_type=urn%3Aopenid%3Aparams%3Agrant-type%3Aciba

Response body

{"token_type":"Bearer","id_token":"eyJraWQiOiJuZGlfc3RnXzAxIiwidHlwIjoiSldUIiwiYWxnIjoiRVMyNTYifQ.eyJhdWQiOiJpTUJ3MlhkR2VHanRYRVl4TURoT1RxUnN5a000dHRaZiIsInN1YiI6InM9Uzg4MjkzMTRCLHU9MWMwY2VlMzgtM2E4Zi00ZjhhLTgzYmMtN2EwZTRjNTlkNmE5IiwiYW1yIjpbInB3ZCIsInN3ayJdLCJpc3MiOiJodHRwczovL3N0Zy1pZC5zaW5ncGFzcy5nb3Yuc2ciLCJleHAiOjE3Mzk0OTc3NDgsImlhdCI6MTczOTQ5NzE0OH0.BxXLysNFj7TKZBydqXICOCzLzQyylt_Gde18_lSLq4ZcWNz8TY3ZGT_DXU5dWkBEJ4OSaDcEfpxpwNdd-MeEDA"}

Response fields

Path
Type
Description

token_type

String

The type of token being requested, Bearer only so far.

id_token

String

The ID token with relevant claims in JWT format signed by the ASP. Note that the example response body shows a JWS (3-part structure separated by dots), but the format will differ for a JWS in JWE (5-part structure). See below for more details about the ID token structure.

Error Responses

The table below shows the list of common error codes that may be returned for this endpoint. RPs must take note to only re-poll the token endpoint for scenarios as specified below.

Important

Note that only the error field in the JSON response should be used to determine the error scenario. Do NOT use the error_description field to determine the error scenario. Singpass reserves the right to change the content of the error_description field without prior notice to RPs.

Error code (returned in error field)

Error scenario

Can perform re-poll?

authorization_pending

The session is still pending as the end-user has not authenticated yet.

Yes

access_denied

End-user rejected the authentication via SP mobile app.

No

expired_token

The authentication session has expired or is not found.

No

unauthorized_client

RP is not authorized to perform this flow.

No

invalid_client

RP failed client assertion authentication.

No

invalid_grant

-

No

invalid_request

-

No

server_error

-

No

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:

Client Profile

sub Claim Content

ID token format

direct

UUID only (eg. u=32af8b7d-ad1d-4c25-8dc7-0a981b533000)

JWS

direct_pii_allowed

Regular NRIC holders: NRIC and UUID (eg. s=S1234567A,u=32af8b7d-ad1d-4c25-8dc7-0a981b533000)

Singpass Foreign Account (SFA) holders: Singpass User ID (UID), Foreigner ID (FID), Country-of-Issuance (COI) and UUID (eg. s=Y7613265T,fid=G730Z-H5P96,coi=DE,u=e2af740e-25b4-4b19-b527-494670952cb0)

This class of users were previously known as "Foreign Unique Account" or "Singpass Foreign Unique Account" users. Only designated relying parties are able to have SFA users authenticate & complete token exchange.

JWS in JWE (encrypted with client’s JWK)

See section below for more details about the JWE format.

bridge (special case internal use only)

NRIC and UUID (eg. s=S1234567A,u=32af8b7d-ad1d-4c25-8dc7-0a981b533000)

JWS

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

  • Authentication Tag

JWE Header

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

example

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

Overview of a JWS

  • JWS Header

  • Payload (containing claims)

  • Signature

JWS Header

example

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

JWT Claims

The JWS ID token will contain the following claims.

example

{
  "aud" : "iMBw2XdGeGjtXEYxMDhOTqRsykM4ttZf",
  "sub" : "s=S8829314B,u=1c0cee38-3a8f-4f8a-83bc-7a0e4c59d6a9",
  "amr" : [ "pwd", "swk" ],
  "iss" : "https://stg-id.singpass.gov.sg",
  "exp" : 1739497748,
  "iat" : 1739497148
}
Path
Type
Description

sub

String

aud

String

iss

String

iat

Number

exp

Number

amr

Array

Authentication method references. Example values are ["face"], ["fv"], ["fv-alt"], ["otp"], ["pwd","fv"], ["pwd","otp-email"], ["pwd","sms"], ["pwd","swk"], ["pwd"], ["sso"]. Note that this list is non-exhaustive, and Singpass reserves the right to introduce new values without prior notice to RPs.

Client JWK Requirements

The client must provide the public key(s) during onboarding, and they can do so only via ONE of the following forms:

  • Provide a JWKS in a JSON format.

Signing key is always required for both direct and direct_pii_allowed clients. Encryption key is only required for direct_pii_allowed clients. direct_pii_allowed clients must ensure that the provided JWKS or the resource returned by the JWKS URL contains both the signing and encryption keys.

Tip

JWK for signing

Clients are allowed to provide multiple signature keys in the JWKS / hosted on the JWKS url provided during client creation.

The signature JWK should have the following attributes:

    • Will be used by Singpass to select the relevant key to verify the client assertion

  • Must be an EC key, with curves: P-256, P-384 or P-521 (NIST curves, aka secp256r1, secp384r1, secp521r1 respectively)

Example EC signing key using P-256 and a timestamped key Id

{
    "kty": "EC",
    "use": "sig",
    "kid": "sig-2021-01-15T12:09:06Z",
    "crv": "P-256",
    "x": "Tjm2thouQXSUJSrKDyMfVGe6ZQRWqCr0UgeSbNKiNi8",
    "y": "8BuGGu519a5xczbArHq1_iVJjGGBSlV5m_FGBJmiFtE"
}

Key Rotation

Relying parties can rotate their signing keys in a self-driven manner. To do this with zero downtime the Relying party must

  • support use of JWKS URLs and be onboarded as such

  • ensure their replacement signing key has a different key ID (kid) to the original key

  • ensure their replacement signing key matches the other cryptographic key requirements

To do this with zero downtime, the following procedure should be followed by the Relying Party:

Time
Action

Prep

Relying party generates a new signing key pair (K2) supported for signing.

T0

Relying party adds public key K2 to its JWKS endpoint (and leaves K1 on the endpoint)

T0 - T+1 hour

Singpass' cache will expire, and re-retrieves the relying party’s published keys from their JWKS endpoint which now includes K2

> T+1 hour

Relying party changes their system to start signing client assertions using the new signing key K2

Clean Up

Post-validation, relying party can remove key K1 from their JWKS endpoint when they are comfortable their new signing key is working

JWK for encryption

Singpass will select the strongest available, supported encryption key from either a local JWKS, or JWKS URL to encrypt returned ID tokens for those relying parties who require any PII in the ID token.

The encryption JWK must have the following attributes:

    • The key ID will be specified in the returned JWE header so that clients can pick the right key for decryption

  • Must have key type (kty) of EC

Key Type (kty)

EC

Status

Required for new Relying Parties

Key encryption algorithm (alg)

ECDH-ES+A128KW ECDH-ES+A192KW ECDH-ES+A256KW

Curve (crv)

P-256 (NIST, aka secp256r1) P-384 (NIST, aka secp384r1) P-521 (NIST, aka secp521r1)

Example EC encryption key using P-256 and a timestamped key Id; asking us to encrypt the CEK using ECDH-ES+A128KW

{
    "kty": "EC",
    "use": "enc",
    "kid": "enc-2021-01-15T12:09:06Z",
    "crv": "P-256",
    "x": "xom6kD54yfXRPvMFVYFlVjUKzmNhz7wf0DP_2h9kXtY",
    "y": "lrh8C9c8-SBJTm1FcfqLkj2AnHtaxpnB1qsN6PiFFJE",
    "alg": "ECDH-ES+A128KW"
}

Key Preference

If the relying party exposes multiple supported encryption keys, Singpass will select the key to use for encrypting tokens based on the following logic:

  1. prefer any EC key (kty) matching the above requirements

  2. prefer EC keys with stronger crv (curve) above EC keys with weaker curve

  3. prefer EC keys with stronger alg key wrapping above weaker ones

  4. otherwise pick the first compatible key we find

Key Rotation

Relying parties can rotate their encryption keys in a self-driven manner. To do this with zero downtime the Relying party must

  • support use of JWKS URLs and be onboarded as such

  • have the ability to decrypt tokens produced with either one of two different encryption keys based on either

    • selecting the correct decryption key by its key ID (kid)

    • trial-and-error decryption against multiple keys in a collection

  • ensure their replacement key matches the other cryptographic key requirements noted above

To do this with zero downtime, the following procedure should be followed by the Relying Party:

Time
Action

Prep

Relying party generates a new encryption key pair (K2) supported for decryption. The existing key pair (K1) is still available for decryption of ID tokens

T0

Relying party removes public key K1 and adds public key K2 on its JWKS endpoint

T0 - T+1 hour

Singpass' caches will expire at any (indeterminate) time within this period, and start encrypting tokens with new encryption key K2.

T0 - T+1 hour

Relying party may be receiving tokens encrypted with either K1 or K2 keys throughout this period; and must be able to decrypt either.

> T+1 hour

Relying party can remove support for decrypting with the previous K1 key

JWKS URL Service Level Expectations

Singpass requires that any JWKS is published on an endpoint that

  • is served behind HTTPS on port 443 using a TLS server certificate issued by a standard publicly verifiable CA issuer (no private CAs), with complete cert chain presented by the server

  • is publicly accessible (no IP whitelisting, mTLS or other custom HTTP header requirements outside standard HTTP headers such as Content-Type, Accept)

  • is able to respond in a timely fashion with respect to the below configuration

Per try timeout

3s

Max attempts

3

Cache duration for retrieved JWKS

1h

Note

While the above is a technical requirement; the user experience of your users may be affected if we are unable to retrieve your JWKS in a timely fashion upon our cache expiry due to slower token exchanges with your backend. We recommend aiming for this response to be as fast as possible based on an in-memory cache; or simple static asset retrieval.

If Singpass fails to retrieve a valid JWKS from the provided URL after cache expiry, the relying party’s token exchange will fail with an OAuth2/OIDC invalid_client error in these circumstances:

  • if client assertions are used, and we are unable to validate the relying party’s assertion using their signing key

  • if encryption of returned ID tokens is required, and we are unable to retrieve the relying party’s preferred encryption key

The recipient that the JWT is intended for. This must match the issuer field in the response of the OpenID discovery endpoint (). e.g.

The time at which the JWT was issued.

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

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

See for more details.

The JWE will contain these standard headers. Refer to for more information about each header.

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

The JWS ID token will contain these standard headers. Refer to for more information about each header.

The principal that is the subject of the JWT. Contains a comma-separated, key=value mapping that identifies the user; possibly including multiple alternate IDs representing the user. The keys included vary by the profile of the OIDC client, and the user type, however the minimal format is u=<UUID> where UUID represents the user’s globally unique identifier.

The client_id of the relying party.

The principal that issued the JWT.

The time at which the JWT was issued.

The expiration time on or after which the JWT MUST NOT be accepted for processing. Defaults to 10 minutes since "iat".

Clients are expected to provide public keys to Singpass in the format. These public keys will be used in the following (non-exhaustive) scenarios:

Signature JWK used to verify the signature of the presented during token request.

Encryption JWK used to which contains the user’s PII.

Host the JWKS on a publicly accessible URL. This endpoint must be compatible with Singpass' .

is a useful open-source tool to generate different types of JWK for signing and encryption; compliant with Singpass' broad requirements on structure. While we DO NOT suggest this as a secure way to generate your real keypair (including private key); this can be a useful tool to understand how JWK works; and how it is represented for signing and encryption purposes; while you are reviewing against our supported algorithms below.

The signing JWK will be used to verify the provided during /token request, thereby authenticating the client.

Must have key use of value sig per

Must contain a key ID in the standard kid field per

The encryption JWK will be used to requested from the /token endpoint.

Must have key use of value enc per

Must contain a key ID in the standard kid field per

Must specify the appropriate key encryption alg the relying party wants Singpass to use, consistent with the key type/curve (kty), and meet the requirements below on allowed alg/curve/key sizes, consistent with

https://datatracker.ietf.org/doc/html/rfc7516#section-3.1
https://tools.ietf.org/html/rfc7515#section-4
JWS
https://tools.ietf.org/html/rfc7515#section-4
JWK
rfc7517#section-4.2
rfc7517#section-4.5
rfc7517#section-4.2
rfc7517#section-4.5
RFC7518 - JSON Web Algorithm specification
this RFC spec documentation
Error Responses
JWS ID Token
client assertion JWT
encrypt an ID token
service level expectations
client assertion JWT
encrypt ID tokens
https://id.singpass.gov.sg/.well-known/openid-configuration
https://id.singpass.gov.sg
https://tools.ietf.org/html/rfc7519#section-4.1.6
https://tools.ietf.org/html/rfc7519#section-4.1.4
https://tools.ietf.org/html/rfc7519#section-4.1.2
https://tools.ietf.org/html/rfc7519#section-4.1.3
https://tools.ietf.org/html/rfc7519#section-4.1.1
https://tools.ietf.org/html/rfc7519#section-4.1.6
https://tools.ietf.org/html/rfc7519#section-4.1.4
mkjwk.org