1. Authorization Request
Note that the testing environment for the FAPI 2.0 Authentication API is not yet ready. It will be ready in December 2025. If you are integrating now, please refer to Singpass Authentication API instead.
The first step in the Singpass authentication flow involves redirecting users to the Singpass login page. As Singpass requires the use of Pushed Authorization Requests (as defined in RFC 9126), you will need to perform two steps to do this:
Send a POST request to the
pushed_authorization_request_endpoint
defined in our authorization server's OpenID configuration.Construct the authorization URL, and redirect the user to this URL.
We require Pushed Authorization Requests as a security measure to prevent request parameters from being tampered by malicious parties.
More details about these steps are provided below.
1. Sending the pushed authorization request
The pushed authorization request is a HTTP POST request that is sent to the pushed authorization request endpoint.
Your request should contain a request body in the application/x-www-form-urlencoded
format. The request body supports a lot of parameters, which can be divided into several groups: parameters specified by basic OIDC, parameters for PKCE, parameters for DPoP, and Singpass-specific parameters.
Basic OIDC Parameters
These are parameters that are specified as part of the original OIDC specifications. More information about them can be viewed in the official specifications.
response_type
The authorization processing flow to be used.
Only the value code
is supported, as mandated by FAPI2.0 specifications.
scope
A space-delimited string, representing a list of scopes that you are requesting.
The scopes that you request will determine the data that is returned in the ID token and in the userinfo endpoint.
For Login apps, the only supported scopes are openid
and sub_account
.
A space-delimited string representing a list of scopes. See our Data Catalog for the allowed values.
The openid
scope must be specified, as per the OIDC specifications.
In addition to the scopes listed in the Data Catalog, the sub_account
scope is also supported. See Parsing the ID token for more details.
state
A session-based, unique, and non-guessable value that you should generate per auth session. This is used to mitigate Cross-Site Request Forgery (CSRF) attacks.
This parameter should be uniquely generated for each request and set by your backend. The generated value should be persisted in the backend and associated with your user's session, as it will be needed later. This string must be generated in a cryptographically secure way, and should ideally be at least 30 characters long. We recommend using a version 4 UUID for this purpose.
A string with a maximum length of 255 characters. It must match the regular expression pattern [A-Za-z0-9/+_-=.]+
.
nonce
A session-based, unique, and non-guessable value that you should generate per auth session. This is used to mitigate replay attacks.
Just like the state
parameter, this parameter should be uniquely generated for each request and set by your backend. The generated value should be persisted in the backend and associated with your user's session, as it will be needed later.
This string must be generated in a cryptographically secure way, and should ideally be at least 30 characters long. We recommend using a version 4 UUID for this purpose.
A string with a maximum length of 255 characters.
We recommend using a randomly-generated version 4 UUID for this purpose.
client_id
The client ID of your registered client, provided by Singpass during app onboarding. It is the App ID found at the top of your app configuration page
A 32-character case-sensitive alphanumeric string.
redirect_uri
The URL that Singpass will eventually redirect the user to after the user completes the login process using the Singpass App. The value will be validated against the list of redirect URLs that were pre-registered with Singpass during onboarding.
URL
acr_values
A string indicating your preference on the level of assurance required for this authentication. Multiple values, in descending order of preference, may be provided as a space-delimited string. Should multiple values be provided, we will use the first available level of assurance for the authentication.
Optional. The possible values are:
urn:singpass:authentication:loa:2
This refers to an assurance level of 2, meaning that only 2FA is required
urn:singpass:authentication:loa:3
This refers to an assurance level of 3, meaning that face verification as a third factor is required. Note that you will incur charges starting from 1 Jan 2026 should you opt for an assurance level of 3.
client_assertion_type
The type of client assertion.
Must be the string urn:ietf:params:oauth:client-assertion-type:jwt-bearer
, as mandated by OIDC specifications.
client_assertion
Your client assertion, which is used for authentication. Refer to Generation of Client Assertion for instructions on how this should be generated.
A string containing the signed JWT.
PKCE Parameters
These are parameters used for Proof of Key Code Exchange (PKCE), which is an additional security measure put in place to protect the authorization code against misuse by malicious actors.
Read our guide on PKCE to understand what these parameters are for and how to generate the code_challenge
.
code_challenge
The base64url encoded SHA256 hash of a randomly generated code_verifier
.
A base64url-encoded string.(note: base64url encoding is not the same as base64 encoding)
code_challenge_method
The method used to generate the code_challenge
from the code_verifier
Only the value S256
is supported, as mandated by FAPI 2.0 specifications
DPoP Parameters
These are parameters used to perform authorization code binding to your DPoP key, which is a further security measure to protect the authorization code against misuse by malicious actors.
dpop_jkt
The JWK Thumbprint of your proof-of-possession public key. The JWK thumbprint should be computed using the SHA256 hash algorithm, and encoded using base64url.
String
Note that dpop_jkt
is only required if your request does not contain the DPoP header (which contains the DPoP Proof JWT).
For simplicity, we recommend sending the DPoP header in the request rather than using the dpop_jkt
request parameter, as you will also need to implement DPoP header generation in later steps.
Singpass-Specific Parameters
These are parameters which are not part of any standard, but are instead specific to Singpass.
authentication_context_type
A value selected from a predefined list describing the type of transaction that your user is performing the authentication for. This will be used for anti-fraud purposes.
Mandatory for Login apps, and not allowed for Myinfo (v5) apps.
The list of possible values is provided below.
authentication_context_message
A string value providing context on what users are performing authentication for. This will be displayed to users when they are performing authentication.
String. Optional, and allowed only for Login apps.
redirect_uri_https_type
This value describes the type of redirect that you intend to perform. You should specify this as app_claimed_https
if you are performing a redirection to a mobile app via an App-claimed https URL.
Either app_claimed_https
or standard_https
.
This field is optional; it defaults to standard_https
if not provided.
app_launch_url
This value is only required if your authentication journey starts and ends for an iOS mobile app. This should be an iOS App Link which will bring the user back to your application after they complete authentication on the Singpass app.
Optional. This should be an iOS App Link.
Possible authentication_context_type values
You should select an appropriate authentication_context_type
value depending on your use case. The possible values for each type of use case are shown below.
Response
Successful Response
If the request was successful, you will receive a response in JSON format which contains the following parameters:
request_uri
This is a reference to the payload that you have sent in this request. This will be needed in the next step
String
expires_in
This is a number, in seconds, representing the lifetime of the request_uri
Number. Maximum allowed value is 600
Error Response
If there was a problem with the request, you will receive a response in JSON format which will instead contain these parameters:
error
An error code identifying the type of error that has occurred.
This will be an enum value. The possible values are detailed below.
error_description
A human-readable text description of the error.
String. This is optional.
error_uri
URI of a web page that includes additional information about the error
URL. This is optional.
state
This will be the same state parameter passed in the authorization request.
A string with a maximum length of 255 characters. It must match the regular expression pattern [A-Za-z0-9/+_-=.]+
Possible error values
The table below lists the possible values of error
that we may return:
invalid_request
The request had missing or invalid parameters. You should ensure that all the parameters follow the specifications listed above. This error will also be returned if you did not send either the DPoP
header or the dpop_jkt
parameter.
invalid_client
This error may occur if your client assertion could not be verified. This is most commonly caused by a malformed JWKS, or an incorrectly generated client assertion.
Refer to our guides on client assertions and JWKS, and make sure that your implementation follows both of these guides.
This can also be caused by an invalid client_id
being passed. Check that your client_id
is correct, and that your app is currently active.
invalid_scope
The scope
parameter that you have provided is invalid. This is typically caused if you did not include the openid
scope, or if you are requesting for a scope which your app is not allowed to request.
If requesting for a new scope, you will need to edit your app and add the new scope into the list of your app's allowed scopes.
invalid_dpop_proof
The DPoP
header which you have provided is invalid, expired, or malformed. Read our DPoP guide and ensure that your implementation follows the instructions in the guide.
server_error
The server encountered an unexpected error. You should check error_description
to understand what was the cause of the error.
This error can potentially be caused by your JWKS endpoint not being reachable. Read our guide on JWKS and ensure that you follow the requirements. In particular, your JWKS endpoint must be publicly accessible and should respond in a timely manner.
If the cause was not your JWKS endpoint, you may perform up to 3 retries using an exponential backoff strategy. If the request still fails, you should guide users to alternative authentication methods.
temporarily_unavailable
The server is temporarily unavailable to handle the request. You may perform up to 3 retries using an exponential backoff strategy. If the request still fails, you should guide users to alternative authentication methods, or to guide them to try again some time later.
2. Redirecting the user to the authorization URL
After you complete the pushed authorization request, the next step is to redirect the user to open the authorization URL in their browser.
The base URL for the authorization URL can be located as the authorization_endpoint
field in the authorization server metadata. You will only need to attach two query parameters to the authorization endpoint to form the authorization URL:
client_id
The client ID of your registered client, provided by Singpass during app onboarding. It is the App ID found at the top of your app configuration page.
This must be the same client ID that you passed in the request body of the pushed authorization request.
request_uri
The request_uri
returned by the pushed authorization request.
Once you have redirected the user to the authorization URL, the next step would be to wait for the user to complete authentication. Once they complete authentication, they will be redirected back to the redirect_uri
that you specified. View the next page to understand how to handle the redirect.
Last updated
Was this helpful?