Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
If you are using one of the following TypeScript / JavaScript frameworks, you can refer to our in-depth guides:
Integrating with TypeScript and JavaScript Node.js applications
If you are using one of the TypeScript / JavaScript frameworks below, you may refer to our in-depth guides:
If not, read on for a framework-agnostic Quick Start in the next section.
The sgID SDK is meant to be used within server-side code (i.e. your backend code). As such, the following steps contain code snippets that should only be run on the server. If you would like to view more details about how your frontend should interact with your backend, please view one of our Framework Guides.
You should generate a new pair for each authorization request, and store the code verifier somewhere you can retrieve it when your user returns from logging into sgID (e.g. in the user's session).
You should store the nonce somewhere you can retrieve it when your user returns from logging into sgID, likely in the same place that you store the code verifier.
After your user logs in to sgID, they will be redirected to your redirect URI with the authorization code (code
) in the query parameters. At this point, you should retrieve the code verifier and nonce from where they were stored in steps 2 and 3 respectively.
The sub
is an end-user's unique sgID identifier, and is used together with the access token in the next step to retrieve the user's data. Feel free to use the sub
to identify your user in your application as necessary.
The final step is to retrieve the data, which will contain the scopes requested in step 3.
For more detailed documentation for each function, visit our API reference.
sgID is a Singapore government identity provider that allows Singapore residents to authenticate with applications and share government-verified data about themselves via the Singpass mobile app.
By default, apps that have integrated with sgID can request for the user's full name.
Note that Singapore government public officers will have access to the full data catalog after they verify their email in our developer portal.
sgID is completely free to use! There are no integration or usage costs associated with sgID.
Other shortcuts:
Authenticate with sgID
Enforce end-to-end encryption of the end user's data
Express (with Single-Page App frontend)
Some examples of products that have integrated with sgID are Singapore's and .
sgID comes shipped with your . That means anyone with the Singpass mobile app can log in with sgID! Check out our to experience the login flow for yourself!
sgID is publicly available for integration. Use your Singpass mobile app to log into our to generate credentials for your app!
The full list of data fields that sgID supports are available at our page. If your app requires access to more data fields, you can file a service request to sgID via this .
If you're ready to try out sgID, get started .
If you've already registered your client, start .
if you have any other questions!
Before you start integrating with sgID, you will need to with sgID. After registration, you will receive sgID client credentials, which include OAuth 2.0 client credentials and a private key that identifies your client. These credentials are important for your application to:
We highly recommend integrating with sgID using one of our SDKs to simplify the .
If you do not wish to integrate with sgID using our SDKs, feel free to refer to our . The guide discusses how to which is useful if you are using your own OpenID Connect client.
First off, you will need to register a client on the sgID Developer Portal. This will provide you with the OAuth 2.0 credentials necessary to authenticate your client with sgID, as well as a private key to decrypt user data.
Click the link below to visit the developer portal and start the registration process!
To register your client, you need to:
Before you can register your client, you will have to log in to the sgID Developer Portal using your Singpass mobile app.
Before you can register your client, you will have to verify your email address (preferably your work email).
Upon login, you will be presented with this view:
Click on the "Register new client" button. When registering a client, you will be prompted to fill in the following details.
Name
Your client display name. This will be displayed to the end user when they are logging in to your app with the Singpass mobile app.
Description
A brief description of the purpose of your client application. This will be displayed to the end user when they are logging in to your app with the Singpass mobile app.
Scopes
Redirect URLs
The redirect URLs that sgID will be allowed to redirect to after the end user authenticates with the Singpass mobile app. This should be the endpoint of your own application. If you are following along with the Framework Guides, please refer to the respective pages for the redirect URL to register.
After completing registration, your client credentials will be generated. Download these credentials and store them in a safe place. The fields in the credentials are as follows.
id
This is your client ID and it is a unique string that identifies your client.
secret
This is your client secret and it is a 32-character string used for exchanging the authorization code for a token.
scopes
publicKey
The RSA-2048 Public Key used by sgID to encrypt data to be sent to your application
privateKey
The RSA-2048 Private Key that will be used by your application to decrypt received data
The maximum list of that your app will be authorized to access. Please refer to the for the full list of scopes offered by sgID.
The maximum list of that your app is authorized to access.
This page contains comprehensive API documentation for the TypeScript / JavaScript SDK. If you're looking to get started quickly, visit our quick start or our framework-specific guides.
The source code can be found on GitHub.
Converts a private key in PKCS1 format to PKCS8.
Parameters
<string>
Private key as a string.
Returns
<string>
Private key in PKCS8 format.
Calculates the S256 code challenge for a provided code verifier.
Parameters
<string>
The code verifier.
Returns
<string>
The calculated code challenge.
Generates the random code verifier.
Parameters
<number>
(Optional) The length of the code verifier to generate. Defaults to 43.
Throws
Error
if length is < 43 or > 128.
Returns
<string>
The generated code verifier.
Generates a challenge pair where code_challenge
is the generated S256 hash from code_verifier
.
Parameters
<number>
(Optional) The length of the code verifier. Defaults to 43.
Throws
Error
if length is < 43 or > 128.
Returns
<Object>
codeChallenge: <string>
S256 code challenge generated from the code verifier.
codeVerifier: <string>
Class which allows you to interact with the sgID API.
Initialises an SgidClient instance.
Parameters
<Object>
clientId: <string>
Client ID provided during client registration.
clientSecret: <string>
Client secret provided during client registration.
privateKey: <string>
Client private key provided during client registration.
redirectUri: <string>
(Optional) Redirection URI for user to return to your application after login. If not provided in the constructor, this must be provided to the authorization_url and callback functions.
hostname: <string>
(Optional) Hostname of OpenID provider (sgID). Defaults to "https://api.id.gov.sg".
Generates authorization url to redirect end-user to sgID login page.
Parameters
<Object>
state: <string>
(Optional) A string which will be passed back to your application once the end-user logs in. You can also use this to track per-request state.
scope: <string> | <string[]>
(Optional) Scopes being requested. Can be provided as a string array or a space-concatenated string. "openid" must be provided as a scope. Defaults to "openid myinfo.name".
nonce: <string> | <null>
(Optional) Random, unique value to associate a user-session with an ID Token and to mitigate replay attacks. Set as null
to omit the nonce. Defaults to a randomly generated nonce if unspecified or set as undefined
.
redirectUri: <string>
(Optional) The redirect URI used in the authorization request. If this param is provided, it will be used instead of the redirect URI provided in the SgidClient constructor. If not provided in the constructor, the redirect URI must be provided here. Defaults to the redirectUri
provided in the constructor.
codeChallenge: <string>
The code challenge generated from generatePkcePair()
.
Throws
Error
if redirect URI is provided in neither the constructor nor this function.
Returns
<Object>
url: <string>
Generated authorization url.
nonce: <string> | <undefined>
Provided nonce, randomly generated nonce, or undefined
(based on nonce input). Should be stored in the user's session so it can be retrieved later for use in callback
.
Exchanges authorization code for access token.
Parameters
<Object>
code: <string>
Authorization code returned in query params via the redirect URI after login.
nonce: <string> | <null>
(Optional) Nonce returned from authorizationUrl
(Set as null
if nonce was set as null
in authorizationUrl
).
redirectUri: <string>
(Optional) Overriding redirect URI used in authorizationUrl
(if provided). Defaults to the redirectUri
provided in the constructor.
codeVerifier: <string>
Code verifier for the code challenge provided in authorizationUrl
.
Throws
Error
if call to token endpoint fails.
Error
if call to JWKS endpoint fails.
Error
if ID token validation fails.
Error
if access token validation fails.
Returns
<Promise<Object>>
sub: <string>
Sub (subject identifier claim) which is the end-user's unique ID.
accessToken: <string>
Access token used to request user info.
Retrieves verified user info and decrypts it with your private key.
Parameters
<Object>
sub: <string>
Sub obtained from callback
.
accessToken: <string>
Access token obtained from callback
.
Throws
Error
if call to userinfo endpoint fails.
Error
if sub returned from userinfo endpoint does not match sub passed to this function.
Error
if decryption fails.
Returns
<Object>
sub: <string>
Represents a unique identifer for the end-user.
data: <Record<string, string>>
A JSON object containing end-user info where the keys are the scopes requested in authorizationUrl
.
If you are using one of the following Python frameworks, you can refer to our in-depth guides:
sgID provides libraries and examples that make integrating your apps with sgID a breeze. We currently offer SDKs and examples in the following programming languages:
If your app uses a language that we do not have an SDK for, or if you would like to implement your own sgID integration, visit our guide on Custom Integration.
Integrating with sgID in a Python application
If you are using one of the Python frameworks below, you may refer to our in-depth guide:
If not, read on for a framework-agnostic Quick Start in the next section.
The sgID SDK is meant to be used within server-side code (i.e. your backend code). As such, the following steps contain code snippets that should only be run on the server. If you would like to view more details about how your frontend should interact with your backend, please view one of our Framework Guides.
You should generate a new pair for each authorization request, and store the code verifier somewhere you can retrieve it when your user returns from logging into sgID (e.g. in the user's session).
You should store the nonce somewhere you can retrieve it when your user returns from logging into sgID, likely in the same place that you store the code verifier.
After your user logs in to sgID, they will be redirected to your redirect URI with the authorization code (code
) in the query parameters. At this point, you should retrieve the code verifier and nonce from where they were stored in steps 2 and 3 respectively.
The sub
is an end-user's unique sgID identifier, and is used together with the access token in the next step to retrieve the user's data. Feel free to use the sub
to identify your user in your application as necessary.
The final step is to retrieve the data, which will contain the scopes requested in step 3.
For more detailed documentation for each function, visit our API reference.
This page provides a step-by-step guide on how to integrate the TypeScript SDK in a Next.js (>= 13.4) project with server-side rendering (SSR) using the app
router, server components, and middleware.
To illustrate our example, we will create a demo app which will allow you to retrieve your user's name and favorite ice cream flavor after they log in with sgID.
If you have not already obtained your client credentials via registration, please register your client before proceeding.
For this example, you should add:
1. [openid, myinfo.name]
as the scopes and
2. http://localhost:5001/success
as a redirect URL
To run the example locally, clone from our source code by running:
Update your .env
file with your client credentials.
Visit http://localhost:5001 to check that your app is running.
If you click on 'Login with Singpass' and authenticate with your Singpass mobile app, you should see your user info on the success screen.
In this section, we'll break down the different steps that our example app goes through.
In this step, we will create an instance of our SgidClient
class which will help us to interface with the sgID server.
In the .env
file created from the previous step, fill out your sgID credentials.
Next, Initialize the SDK by calling the constructor and providing your client credentials.
To maintain session data across requests, we will need to initialize an in-memory store for our server.
The purpose of this middleware is to generate a session ID and set it in the browser's cookies when the user visits the site. This session ID is important for the server to identify the browser and track the session data through the login flow.
Now, we need to create a button to redirect the browser to the /login
page. Additionally, we will be creating an ice cream flavour selector in order to demonstrate the OAuth 2.0 protocol's ability to carry over state.
In the following examples, we will not include any styling in order to keep the code snippet short. If you would like to view and interact with an example with styling, feel free to refer to the source code.
As we will be using useState
, this component will be a client component.
Next, add the log in button to the home page as such.
/login
page which redirects to the authorization URLWhen the user clicks on the 'Login with Singpass' button, it should direct them to the /login
page which will generate the authorization URL to redirect the browser to.
The server function handleLogin
will do the following.
Retrieve the session ID from the browser cookies (that was set by the middleware)
Generate a PKCE pair (consisting of code challenge and code verifier)
Generate an authorization URL
Store the code verifier in the in-memory store with the session ID as the key
Redirect the browser to the authorization URL
/success
pageOnce the end-user has successfully authorized your application with their Singpass mobile app, the sgID server will redirect the browser to the provided redirect URL.
When the browser visits this URL, the following will happen.
The authorization code is retrieved from the URL search params
The code is exchanged for an access token
The user info is requested with the access token
The user info is stored in-memory for subsequent requests
The user info is used to generate the HTML page on the server
Now if you run your Next.js app, click on Login with Singpass
and complete the authorization flow with your Singpass mobile app, you should be brought to this success page where you can view your personal details as well as your ice cream flavour selected on the login page.
The purpose of this page is to demonstrate how to retrieve the user data stored in-memory for subsequent requests. We will simply be creating a dummy page that displays the user info just like in the previous step.
If you complete the log in flow once again but click on the 'View user info' button, you will be brought to this /login
page where you can view user data. To ensure that the user info has been properly stored in the in-memory store, try refreshing the page - you should see that the user info can still be fetched by the page.
You have reached the end of the Next.js (SSR) step-by-step guide.
The source code for this example can be found here which includes an /logout
page (and middleware) for logging out, styling with Tailwind CSS, and a README on how to run the example locally.
If you want to find out more about how sgID works, click here to learn about the sgID protocol.
If you have more questions about sgID, check out our FAQ for answers to common questions.
This page provides a step-by-step guide on how to integrate the TypeScript SDK in a Next.js project using the pages
router, api
routes and client-side rendering (CSR).
To illustrate our example, we have prepared a demo app which will allow you to retrieve your user's name and favorite ice cream flavor after they log in with sgID.
If you have not already obtained your client credentials via registration, please register your client before proceeding.
For this example, you should add:
1. [openid, myinfo.name]
as the scopes and
2. http://localhost:5001/api/redirect
as a redirect URL
To run the example locally, clone from our source code by running:
Update your .env
file with your client credentials.
Visit http://localhost:5001 to check that your app is running.
If you click on 'Login with Singpass' and authenticate with your Singpass mobile app, you should see your user info on the success screen.
In this section, we'll break down the different steps that our example app goes through.
In this step, we will create an instance of our SgidClient
class which will help us to interface with the sgID server.
In the .env
file created from the previous step, fill out your sgID credentials.
Next, initialize the SDK by calling the constructor and providing your client credentials.
To maintain session data across requests, we will need to initialize an in-memory store for our server.
When an end user clicks on the sign in button on your application (e.g. 'Login with Singpass app'), it should redirect the browser to this endpoint.
The /api/auth-url
endpoint should do the following
Generate a session ID
Generate a PKCE pair (consisting of code challenge and code verifier)
Generate an authorization URL
Store the code verifier in the in-memory store with the session ID as the key
Set the session ID in the browser's cookies
Redirect the browser to the authorization URL
After the user scans the QR code with their Singpass mobile app and authorizes your application to access the specified scopes, the sgID server will redirect the user's browser to the redirect_uri
you specified earlier (either when initializing the SDK or when passed as a parameter to the authorizationUrl
function).
The redirect will include the authorization code and the state (if provided earlier) in the form of query parameters. An example URL would look something like this
The /api/redirect
endpoint should do the following
Retrieve the authorization code from query params, and the session ID from browser cookies
Retrieve the code verifier from the in-memory store
Exchange the authorization code and code verifier for the access token
Store the access token and sub in the in-memory store
Redirect the browser to a logged in page (or any page of your choice)
Once the browser has been redirected to a logged in/success page, your app can make a GET
request to this endpoint which will use the access token stored in session to request user info from the sgID server.
The /api/userinfo
endpoint should do the following:
Retrieve the session ID from browser cookies
Retrieve the access token from the in-memory store using the session ID
Request user info using the access token
Store user info in the in-memory store
Return the user info
With this step, the API endpoints are completed. In the next 2 steps, we will complete the Next.js application by creating the user interface to interact with these endpoints.
/api/auth-url
Now, we need to create a button to redirect the browser to the /api/auth-url
endpoint.
In the following examples, we will not include any styling in order to keep the code snippet short. If you would like to view and interact with an example with styling, feel free to refer to the source code.
Now when you run your Next.js app and visit http://localhost:5001
, you should see a Login with Singpass
button which when clicked should bring you to the sgID approval page with the QR code.
/logged-in
page to fetch and render user info After the /api/redirect
endpoint completes the request and the user info is stored in the in-memory store, the browser will be redirected to the /logged-in
page.
The redirection to this page also marks that the user has successfully logged in and your application should be able to freely retrieve user info from the in-memory store.
As such, we will make a GET
request to the /api/userinfo
endpoint on this page and render the user info. As with above, we will omit styling from the following example.
Now if you run your Next.js app, click on Login with Singpass
and complete the authorization flow with your Singpass mobile app, you should be brought to this success page where you can view your personal details as well as your ice cream flavour selected on the login page.
You have reached the end of the Next.js (CSR) step-by-step guide.
The source code for this example can be found here which includes a /api/logout
API endpoint for logging out, styling with Tailwind CSS, and a README on how to run the example locally.
If you want to find out more about how sgID works, click here to learn about the sgID protocol.
If you have more questions about sgID, check out our FAQ for answers to common questions.
Integrating a Flask server with sgID
This page provides a step-by-step guide on how to integrate the Python SDK in a simple Flask server. This Flask server will be used as a backend server for a SPA frontend.
To illustrate our example, we have prepared a demo app which will allow you to retrieve your user's name and favorite ice cream flavor after they log in with sgID.
If you have not already obtained your client credentials via registration, please register your client before proceeding.
For this example, you should add:
1. [openid, myinfo.name]
as the scopes and
2. http://localhost:5001/api/redirect
as a redirect URL
To run the example locally, clone from our source code by running:
Update your .env
file with your client credentials.
In separate terminals, run the frontend and the backend.
Ensure that your backend Flask server is running on http://localhost:5001 and visit http://localhost:5173.
If you click on 'Login with Singpass' and authenticate with your Singpass mobile app, you should see your user info on the success screen.
In this section, we'll break down the different steps that our example app goes through.
In this step, we will create an instance of our SgidClient
class which will help us to interface with the sgID server.
In the .env
file created from the previous step, fill out your sgID credentials.
Next, initialize the SDK by calling the constructor and passing in the environment variables.
Before we create the endpoints, we will need to configure the Flask app.
When an end user clicks on the sign in button on your application (e.g. 'Login with Singpass app'), it should make a GET
request to this endpoint to retrieve the authorization URL. The browser is then redirected to this authorization URL.
The /api/auth-url
endpoint should do the following
Generate a session ID
Generate a PKCE pair (consisting of code challenge and code verifier)
Generate an authorization URL
Store the code verifier in the session
Set the session ID in the browser's cookies
Return the authorization URL
After the user scans the QR code with their Singpass mobile app and authorizes your application to access the specified scopes, the sgID server will redirect the user's browser to the redirect_uri
you specified earlier (either when initializing the SDK or when passed as a parameter to the authorization_url
function).
The redirect will include the authorization code and the state (if provided earlier) in the form of query parameters. An example URL would look something like this
The /api/redirect
endpoint should do the following
Retrieve the authorization code from query params, and the session ID from browser cookies
Retrieve the code verifier from session
Exchange the authorization code and code verifier for the access token
Store the access token and sub in session
Redirect the browser to a logged in page (or any page of your choice)
Once the browser has been redirected to a logged in/success page, your app can make a GET
request to this endpoint which will use the access token stored in session to request user info from the sgID server.
The /api/userinfo
endpoint should do the following
Retrieve the session ID from browser cookies
Retrieve the access token from memory using the session ID
Request user info using the access token
Return the user info
Now that your Flask server has been set up properly, you will need to integrate your frontend application with it.
If you have followed the steps from Running the example locally, the frontend and backend examples have already been integrated for you.
However, if you would like to integrate with your own frontend application, there are two main steps you need to implement:
A page with a 'Login with Singpass' button
Click here for the relevant code in the frontend repo.
The button will need to make a GET
request to the /api/auth-url
endpoint and then redirect the browser to the received authorization URL.
Fetching the user info after logging in
Click here for the relevant code in the frontend repo.
After the user logs in, the frontend can make a GET
request to the /api/userinfo
endpoint to retrieve the user info.
You have reached the end of the Flask step-by-step guide.
While these examples should work seamlessly in a local environment (i.e. localhost), they may not work if deployed (specifically if the frontend and backend are deployed on different domains).
This is due to the SameSite
attribute on cookies. For these examples to work in a deployed environment, you would need to either
Utilize a reverse proxy to deploy the frontend and backend on the same domain; or
Set the SameSite
attribute as None
to be able to set cookies on a different domain
If you want to find out more about how sgID works, click here to learn about the sgID protocol.
If you have more questions about sgID, check out our FAQ for answers to common questions.
Some common issues your might face during integration
The internet can be a dangerous place. We use well-established protocols, like OAuth 2.0 and OpenID Connect to communicate with each other in a well-defined and safe manner.
While OAuth 2.0 provided a framework for users to delegate permission to third-party apps (authorization), the internet still lacked a standard way for federating authentication. OpenID Connect (OIDC) extended the OAuth 2.0 protocol by including a new artifact called the ID token, which serves as a proof of authentication. When using Google to log into a third-party app, you are most likely using the OIDC protocol. That app accepts Google's claims that you are who you say you are, and receives your consent to retrieve (your Google) data or take actions on your behalf!
OIDC provides a secure way for users to authenticate with and share data with third-party apps, but by default, it isn't privacy-preserving. The identity provider (Google, in the example above) knows which third-party apps you're communicating with and what data you're sending them.
Converts a private key in PKCS1 format to PKCS8.
Args
private_key (str)
Private key as a string.
Raises
Exception
if private key is invalid.
Returns
str
Private key in PKCS8 format.
Calculates the S256 code challenge for a provided code verifier.
Args
code_verifier (str)
The code verifier.
Returns
str
The calculated code challenge.
Generates the random code verifier.
Args
length (int, optional)
The length of the code verifier to generate. Defaults to 43.
Raises
Exception
if length is <43 or >128.
Returns
str
: The generated code verifier.
Generates a challenge pair where code_challenge
is the generated S256 hash from code_verifier
.
Args
length (int, optional)
The length of the code verifier. Defaults to 43.
Raises
Exception
if length is <43 or >128.
Returns
GeneratePkcePairReturn
: Code challenge and code verifier.
Class which allows you to interact with the sgID API.
Initialises an SgidClient instance.
Args
client_id (str)
Client ID provided during client registration.
client_secret (str)
Client secret provided during client registration.
private_key (str)
Client private key provided during client registration.
redirect_uri (str | None, optional)
Redirection URI for user to return to your application after login. If not provided in the constructor, this must be provided to the authorization_url and callback functions. Defaults to None.
hostname (str, optional)
Hostname of OpenID provider (sgID). Defaults to "https://api.id.gov.sg".
Raises
Exception
if private key is invalid.
Generates authorization url to redirect end-user to sgID login page.
Args
code_challenge (str)
The code challenge generated from generate_pkce_pair()
.
state (str | None, optional)
A string which will be passed back to your application once the end-user logs in. You can also use this to track per-request state.
redirect_uri (str | None, optional)
The redirect URI used in the authorization request. If this param is provided, it will be used instead of the redirect URI provided in the SgidClient constructor. If not provided in the constructor, the redirect URI must be provided here. Defaults to None.
scope (str | list[str])
"openid" must be provided as a scope. Defaults to "openid myinfo.name".
nonce (str | None, optional)
Unique nonce for this request. If this param is not provided, a nonce is generated and returned. To prevent this behaviour, specify None for this param. Defaults to secrets.token_urlsafe(32)
.
Raises
Exception
if redirect URI is provided in neither the constructor nor this function.
Returns
AuthorizationUrlReturn
: Authorization URL and nonce.
Exchanges authorization code for access token.
Args
code (str)
The authorization code received from the authorization server.
code_verifier (str)
The code verifier corresponding to the code challenge that was passed to authorization_url
for this request.
nonce (str | None, optional)
Nonce passed to authorization_url
for this request. Specify None if no nonce was passed to authorization_url
. Defaults to None.
redirect_uri (str | None, optional)
The redirect URI used in the authorization request. If not specified, defaults to the one passed to the SgidClient constructor.
Raises
Exception
if call to token endpoint fails.
Exception
if call to JWKS endpoint fails.
Exception
if ID token validation fails.
Exception
if access token validation fails.
Returns
CallbackReturn
: The sub (subject identifier claim) of the user and access token. The subject identifier claim is the end-user's unique ID.
Retrieves verified user info and decrypts it with your private key.
Args
sub (str)
The sub returned from the callback
function.
access_token (str)
The access token returned from the callback
function.
Raises
Exception
if call to userinfo endpoint fails.
Exception
if sub returned from userinfo endpoint does not match sub passed to this function.
Exception
if decryption fails.
Returns
UserInfoReturn
: The sub of the end-user and the end-user's verified data. The sub returned is the same as the one passed in the params.
You will need to write your own custom sgID integration if your app uses a programming language that sgID does not have a SDK for. This page provides a guide for how to implement this custom integration.
When a user tries to log in to your application with sgID, you need to:
Proof Key for Code Exchange (PKCE) is an OAuth 2.0 enhancement and protects against various potential vulnerabilities such as authorization code interception. A unique PKCE pair must be generated for each request and consists of a code_verifier
and a code_challenge
.
Code verifier
The code_verifier
should be a high-entropy cryptographic random string with an ABNF as follows
Code challenge
The code_challenge
should be generated from the code_verifier
using the S256
code challenge method. The S256
transformation is described below together with the ABNF of the code_challenge
.
The code_challenge
must be sent to the sgID authorization server when initiating an authorization request, whereas the code_verifier
must be provided when exchanging the OAuth authorization code for an access token. This allows the sgID server to verify that the server exchanging the access token is the same server that initiated the request!
Here are some cryptography libraries you could use to generate these values:
To allow your user to login into your app with sgID, you need to create an sgID authorization URL.
Your app should redirect your user's browser to this authorization URL, which will display a QR code that they can scan to authenticate with the Singpass mobile app:
You will need to supply the following query string parameters:
After the user authenticates with the Singpass mobile app, the user's browser will be redirected back to the callback URL you provided, together with the authorization code and a state value.
To exchange the code
for the access token and ID token, make a POST
request to
with the following request body parameters:
You should receive a response with the following attributes:
Example JSON response body:
Once you have the access token, you can use it to request information about the user corresponding to the scopes that you requested. To do so, make a GET
request to
with the access token you received in the previous step. Example request:
You should receive a response with the following attributes:
Example JSON response body:
As part of sgID's privacy-preserving measures, user data is transmitted in encrypted form, so that the sgID server is unable to read the data being transacted. The data is encrypted with a block key, which itself is encrypted with your client's public key so that only your client has access to the block key.
Therefore, to obtain the user data in plaintext, you will need to:
Decrypt the key
received from the user info response with your client's private key. This will give you the block key.
Decrypt the data
received from the user info response with the block key you have just obtained.
Example decryption:
Example of decrypted data:
Integrating an Express server with sgID
To illustrate our example, we have prepared a demo app which will allow you to retrieve your user's name and favorite ice cream flavor after they log in with sgID.
Update your .env
file with your client credentials.
In separate terminals, run the frontend and the backend.
If you click on 'Login with Singpass' and authenticate with your Singpass mobile app, you should see your user info on the success screen.
In this section, we'll break down the different steps that our example app goes through.
In this step, we will create an instance of our SgidClient
class which will help us to interface with the sgID server.
In the .env
file created from the previous step, fill out your sgID credentials.
Next, initialize the SDK by calling the constructor and passing in the environment variables.
Before we can create the endpoints, we will need to configure the Express app.
When an end user clicks on the sign in button on your application (e.g. 'Login with Singpass app'), it should make a GET
request to this endpoint to retrieve the authorization URL. The browser is then redirected to this authorization URL.
The /api/auth-url
endpoint should do the following
Generate a session ID
Generate a PKCE pair (consisting of code challenge and code verifier)
Generate an authorization URL
Store the code verifier in the session
Set the session ID in the browser's cookies
Return the authorization URL
After the user scans the QR code with their Singpass mobile app and authorizes your application to access the specified scopes, the sgID server will redirect the user's browser to the redirect_uri
you specified earlier (either when initializing the SDK or when passed as a parameter to the authorizationUrl
function).
The redirect will include the authorization code and the state (if provided earlier) in the form of query parameters. An example URL would look something like this
The /api/redirect
endpoint should do the following
Retrieve the authorization code from query params, and the session ID from browser cookies
Retrieve the code verifier from session
Exchange the authorization code and code verifier for the access token
Store the access token and sub in session
Redirect the browser to a logged in page (or any page of your choice)
Once the browser has been redirected to a logged in/success page, your app can make a GET
request to this endpoint which will use the access token stored in session to request user info from the sgID server.
The /api/userinfo
endpoint should do the following
Retrieve the session ID from browser cookies
Retrieve the access token from memory using the session ID
Request user info using the access token
Return the user info
Now that your Express server has been set up properly, you will need to integrate your frontend application with it.
However, if you would like to integrate with your own frontend application, there are two main steps you need to implement:
A page with a 'Login with Singpass' button
The button will need to make a GET
request to the /api/auth-url
endpoint and then redirect the browser to the received authorization URL.
Fetching the user info after logging in
After the user logs in, the frontend can make a GET
request to the /api/userinfo
endpoint to retrieve the user info.
You have reached the end of the Express step-by-step guide.
Utilize a reverse proxy to deploy the frontend and backend on the same domain; or
Set the SameSite
attribute as None
to be able to set cookies on a different domain
OAuth 2.0 and OpenID Connect (OIDC) are two widely used identity protocols that help users securely authenticate with and delegate permissions to third-party apps. When you log in to a service with Google, Twitter, or GitHub, you're most likely using OIDC!
Here are some resources for learning more about OAuth 2.0 and OIDC:
As a government identity provider, sgID distinguishes itself from private sector identity providers because it provides Singapore resident data that is verified by the government to be true. Because the data is both signed and separately encrypted with an end user-specific key pair, this allows sgID to verify that the data is not tampered with when the sgID relying party receives it.
One of the key features of the sgID protocol is its privacy-preserving approach. End user data is encrypted with keys held on their device, so the sgID server handling the transaction cannot read the data that is being transmitted. This means that only the end user knows who they've been transacting with, and what information has been transacted.
sgID enforces client-specific identifiers. This means that different sgID relying parties receive different identifiers for the same end user. For example, if Xiao Ming logs into McDonald's with sgID, McDonald's might receive Xiao Ming's data, identifying him with a system ID of abcde
. But if Xiao Ming logs into KFC, with sgID, KFC will receive a different system ID, such as 12345
.
GET
request to the /api/auth-url endpointIf there are no SDKs provided for your programming language, please refer to on how to set up your own integration.
Do not reuse the example code challenge and code verifier provided in the API examples, as this would expose your API requests to PKCE guessing attacks by malicious users. Refer to the example code under the on how to generate valid <code_verifier, code_challenge>
pairs.
If you are facing any other issues with integrating with sgID, please contact us !
In the past, sharing personal information with third-party applications online was relatively simple but posed a significant security risk. It was fairly common to share your username and password, which granted full access to your account and data. This created a vulnerability known as , in which the third party could act maliciously without your knowledge or consent.
To address this issue, the Internet Engineering Task Force (IETF) rolled out the OAuth protocol to enable third-parties to request information or perform actions on your behalf without providing access to your entire account. Today, its current iteration () is widely used all over the internet.
To address these privacy concerns, sgID's protocol builds on top of the OIDC protocol to provide end-to-end encryption so that the identity provider does not know who you're communicating with, and the contents of the data that you're sharing with the third-party app. Read more about the sgID protocol !
This page contains comprehensive API documentation for the Python SDK. If you're looking to get started quickly, visit our or our .
The source code can be found on .
sgID only supports the S256
code challenge method as the plain
method is insecure (see the ) and only exists for backwards compatibility reasons.
Node.js -
Python -
The ID token is signed with sgID's private key. It is highly recommended that you verify the ID token with our public keys, which can be found .
This page provides a step-by-step guide on how to integrate the TypeScript SDK in a simple Express server. This Express server will be used as a .
If you have not already obtained your client credentials via registration, please before proceeding.
For this example, you should add:
1. [openid, myinfo.name]
as the scopes and
2. http://localhost:5001/api/redirect
as a redirect URL
To run the example locally, clone from our by running:
Ensure that your backend Express server is running on and visit .
If you have followed the steps from , the frontend and backend examples have already been integrated for you.
Click for the relevant code in the frontend repo.
Click for the relevant code in the frontend repo.
While these examples should work seamlessly in a local environment (i.e. localhost), they may not work if deployed (specifically if the frontend and backend are deployed on different domains). This is due to the attribute on cookies. For these examples to work in a deployed environment, you would need to either
If you want to find out more about how sgID works, click here to .
If you have more questions about sgID, check out our for answers to common questions.
sgID is an OpenID Connect (OIDC) by the Singapore government. sgID uses a privacy-preserving version of the OIDC protocol. This allows applications to integrate with sgID based on familiar industry standards, while providing privacy guarantees for end users.
sgID's implementation of OpenID Connect (OIDC) supports the standard . This means that integration steps are based on the familiar OAuth 2.0 authorization code flow.
If you're interested in learning more about the design of the sgID protocol, you can refer to the sgID .
response_type
Must be set to code
because sgID only supports the authorization code flow
client_id
Provided to you during client registration
redirect_uri
The callback URL that you provided during client registration
scope
A URL-encoded string of the scopes your client will request for
code_challenge
The code challenge used for PKCE. Used to prevent authorization code interceptions and cross-site request forgery (CSRF)
nonce (optional)
Randomly generated string to be returned in the id_token. Used to prevent replay attacks. Refer to the OpenID Connect documentation for implementation details
state (optional)
A unique and non-guessable value associated with each authentication request about to be initiated
client_id
Provided to you during client registration
client_secret
Provided to you during client registration
code
The value returned to you as part of the callback URL
grant_type
Must be set to authorization_code
redirect_uri
The callback URL that you provided during client registration
code_verifier
A cryptographically random string that was used to generate your code challenge in the authorization request.
access_token
Access Token to be used with retrieving the encrypted payload from user info endpoint
id_token
JWT token with the associated user claims. Encodes the following:
iss (hostname)
sub (end user's unique identifier)
aud (client id)
nonce (only returned if provided in authorization URL)
exp (seconds before auth request and access token expires)
iat (timestamp at which id token was issued)
sub
End user's unique identifier for your client - This is the same value as the sub
claim in the id_token
returned from the previous response.
Note that as part of sgID's privacy-preserving measures, each end user's unique identifier is different for each sgID client
key
An AES-128-GCM symmetric key, or a block key, that is encrypted with your client's RSA-2048 public key.
data
JSON object which contains the data you requested in your application scope. To prevent sgID from reading the data, the payload is encrypted with the block key referenced in the definition for the key
attribute in the same response body.
Refer to the following section for instructions on decrypting the payload.
TypeScript • Javascript
Python
Custom Integration
data
you received from the user info endpointGET
request to the /api/auth-url endpointThis page documents all the breaking changes made to sgID, and contains step-by-step migration guides for existing users.
17 May 2023 - Major release of v2.0 TypeScript SDK. Breaking changes include PKCE and new API method signatures. Deprecation of v1 SDK will take place in 31st December 2023, therefore any existing users who has yet to upgrade their SDK version and implement the necessary code changes for PKCE by then will face disruptions in their applications. Refer to TypeScript SDK v2.0 Major Release for a step-by-step migration guide.
To integrate sgID into your application, you need to understand the different OAuth 2.0 flows based on industry standards. The most popular flows are the authorization code flow (for confidential clients), implicit flow (for public clients), and hybrid flow (for public clients).
Currently, sgID does not support public clients due to the fact that sgID clients need to be able to keep a secret for its end-to-end encryption (E2EE) to work. Therefore, sgID only supports the authorization code flow.
Public clients, such as standalone single-page apps (SPA) or native mobile apps, cannot keep a secret because their source code can easily be inspected to reveal secrets or credentials. As such, any secret for client authentication, such as the OAuth 2.0 client secret or the sgID client private key, is rendered public. This makes it easy to impersonate these clients. As Okta notes, currently "there aren’t any reliable mechanisms for authenticating pure SPA clients in a browser".
Confidential clients, on the other hand, can maintain the confidentiality of their client credentials or use other secure client authentication methods. They consist of two components:
A frontend app, which can be a SPA, native mobile app, or server-side rendered (SSR) frontend, and
A backend server that communicates with the sgID server's OpenID Connect (OIDC) endpoints
Since SPAs or mobile apps cannot keep secrets, they cannot be trusted to communicate with the sgID authorization server. Therefore, all communication between the client and sgID must go through the backend server, and the frontend component is not considered an OAuth client.
sgID uses E2EE to keep the transmission of data from the end user to the client private from sgID itself. For this to work, the client needs its own private key to decrypt the end user's data. Since the private key needs to be kept secret, sgID can currently only support confidential clients.
In this documentation, we will discuss three integration patterns:
These integration patterns will help you implement the OAuth 2.0 flows and integrate sgID into your application while ensuring confidentiality and security.
This document documents the major changes introduced in v2.0.0 sgID TypeScript SDK, and serves as a step-by-step guide for existing v1.x.x sgID TypeScript SDK users to upgrade their version to v2.x.x.
PKCE is introduced, and its implementation is mandated. According to OAuth 2.0 Security Best Current Practice:
For confidential clients, the use of PKCE [RFC7636] is RECOMMENDED, as it provides a strong protection against misuse and injection of authorisation codes as described in Section 4.5.3.1 and, as a side-effect, prevents CSRF even in presence of strong attackers as described in Section 4.7.1.
SgidClient.authorizationUrl()
, SgidClient.callback()
, and SgidClient.userinfo()
now take in a single options object as a parameter, instead of sequential, possibly optional parameters. Refer to SgidClient’s module file SgidClient.d.ts
for implementatino details.
sub
is now required in userinfo()
calls, which can be retrieved from the response returned from callback()
.
In light of all the breaking changes above, users are strongly recommended to refer to the example upgrade path outlined below to safely migrate their applications to v2.x SDK. Deprecation of the v1.x SDK will take place in 31st December 2023, therefore any existing users who has yet to upgrade their SDK version by then will face disruptions in their application(s).
The Developer Documentation has been revamped, containing the newest changes. Users can refer to the documentation for a better understanding of how sgID works.
The code below assumes the following contexts for Client Application:
Client Application is a full stack web application.
Client Application consists of a SPA and an Express back-end server.
Client Application manages state in its back-end server's session.
Refer to the Framework Guides Section for how a Next.js implementation might look like.
Run npm i @opengovsg/sgid-client@2.0.0
(or any newer minor/patch versions released in the future) for all directories that
contain a package.json
file, and
have a dependency to @opengovsg/sgid-client
in the corresponding package.json
file.
authorizationUrl(…)
)For every OAuth request, generate a PKCE pair (consisting of code challenge and code verifier). Do not reuse the same PKCE pairs for any requests.
Call authorizationUrl()
with the correct options object.
Store the Verifier with the corresponding session ID, alongside its state and nonce if applicable:
callback(…)
)Retrieve the code verifier from the session and pass it in callback()
as part of the options object.
userinfo(…)
)Note the inclusion of sub
as one of the fields in the options object.
You should have the v2 SDK successfully integrated into your application!
Q: What if my application does not follow the same architecture as the example Application described?
A: Unfortunately it is infeasible to list out all possible upgrade paths as there are too many possible architectures for an application in practice. However, the example upgrade path should serve as an adequate reference guide for the necessary changes to migrate to v2 SDK.
Q: I'm stuck at Step X and I don't know what to do. How can I proceed?
A: Feel free to drop us a message at this form for further clarification.
Flask (with Single-Page App frontend)
A web server runs the necessary logic to communicate with the sgID server, and generates HTML pages to be sent to the user-agent / browser where it is rendered. The process of generating HTML pages on the server is also known as server-side rendering (SSR).
End user visits a website (generated by the web server) in their browser
Upon clicking on "Login with sgID", the web server generates an authentication URL and sends the authentication URL to the browser
The browser then redirects to the sgID authorization URL, where a QR code is rendered
The end user authorizes the transaction by scanning the QR code with their Singpass mobile app, and consents to share their data with the web server
Upon successful authorization, the sgID server sends the registered redirect / callback URL (associated with the web server) to the browser, which redirects to that URL
The web server receives the authorization code in the callback URL and exchanges it for an access token and ID token using its client ID and client secret
The web server then uses the access token to obtain the end user's data from the sgID server userinfo
endpoint
The web server will then log the end user in and render the logged-in screen
The White Paper describes the design goals of the sgID protocol, and goes into detail on the protocol specifics and how it meets these design goals
As discussed in Integration Patterns, sgID does not support public clients like standalone SPAs or native mobile applications. Therefore, when using a SPA frontend, the client must also maintain a backend server which will interact with the sgID server instead of the frontend. This design pattern is known as backend for frontend (BFF).
The SPA frontend requests a sgID authorization URL from the backend server
The SPA triggers a browser redirect to the sgID authorization URL, where a QR code is rendered
The end user authorizes the transaction by scanning the QR code with their Singpass mobile app, and consents to share their data with the client application
Upon successful authorization, the sgID server sends the registered redirect / callback URL (associated with the web server) to the browser, which redirects to that URL. This URL should be associated with the backend server
The backend server receives the authorization code in the callback URL and exchanges it for an access token and ID token using its client ID and client secret
The backend server then uses the access token to obtain the end user's data from the sgID server userinfo
endpoint
The backend server will then authenticate the end user's SPA session, and subsequently log the end user into their app.
Flask (with Single-Page App frontend)
Frequently asked questions
If you have any questions that aren't answered here, please contact us at this form!
If you have any questions about sgID, please feel free to contact us at this form!
Frequently asked questions
If you have any questions that aren't answered here, please contact us at this form!
What data fields / scopes are provided by sgID?
The following table shows the list of available scopes from MyInfo that a sgID relying party can request. The scopes that your application can access are determined during client registration.
Principle name
myinfo.name
Full name of user printed on NRIC or FIN card. Includes Surname if any
string
e.g. Denise Tan Hui Min
NRIC/FIN
myinfo.nric_number
NRIC number or FIN of user. NRIC number is the unique identifier given to every Singapore Citizens (SC) and Permanent Residents (PR), while FIN is the unique identifier for Foreigners (FIN)
string
e.g. S9876543A
Date of Birth
myinfo.date_of_birth
Date of birth of the user
string
(YYYY-MM-DD)
e.g. 1965-08-09
However, on occasion, you might also observe the following formats for individuals for whom date of birth data is missing:
- (YYYY-MM) e.g. 1965-08
- (YYYY) e.g 1965
Passport number
myinfo.passport_number
Passport number of the user
string
e.g. E35463874W
Passport expiry date
myinfo.passport_expiry_date
Passport expiry date of the user
string
(YYYY-MM-DD)
e.g. 2030-08-09
Mobile number
myinfo.mobile_number
Mobile number of the user
string
(8-digit number without Country Code)
e.g. 87654321
Email address
myinfo.email
Email address of the user
string
e.g. sgid@open.gov.sg
Registered address
myinfo.registered_address
Registered address of the user. For SC/PR - Registered address is the address that is printed on the NRIC card.
string
(with \n)
e.g. 102 BEDOK NORTH AVENUE 4\n#09-128\nSINGAPORE 460102
Sex
myinfo.sex
Gender of the user
string
e.g. MALE
Race
myinfo.race
Race of the user
string
e.g. MALAY
Nationality
myinfo.nationality
Nationality of the user
string
e.g. SINGAPOREAN
Residential Status
myinfo.residentialstatus
Residential status of the user
string
e.g. SINGAPORE CITIZEN
Housing Type
myinfo.housingtype
Housing Type of the user
string
e.g. HDB
HDB Type
myinfo.hdbtype
HDB Type of the user
string
e.g. 4-ROOM FLAT (HDB)
Birth Country
myinfo.birth_country
Birth Country of the user
string
e.g. SINGAPORE
Vehicles Details
myinfo.vehicles
Details of vehicles owned by the user
string
(stringified array of objects with the following attributes:
- vehicle_number
)
e.g. []
or
(MOM) Name of Employer
myinfo.name_of_employer
Name of user's employer registered with MOM
string
e.g. GovTech
(MOM) Workpass Status
myinfo.workpass_status
Workpass status of the user
string
e.g. Active
(MOM) Workpass Expiry Date
myinfo.workpass_expiry_date
Workpass expiry date of the user
string
e.g. 2025-12-04
Marital Status
myinfo.marital_status
Marital status of the user
string
e.g. SINGLE
Mobile Number (Formatted with country code)
myinfo.mobile_number_with_country_code
Mobile number of the user formatted with prefix and country code
string
e.g. +65 81235678
Dialect
myinfo.dialect
Dialect of the user
string
e.g. TEO CHEW
Occupation
myinfo.occupation
Occupation of the user
string
e.g. ACCOUNTANT
Country of Marriage
myinfo.country_of_marriage
Country of Marriage of the user
string
e.g. SINGAPORE
Marriage Certificate Number
myinfo.marriage_certificate_number
Marriage Certificate Number of the user
string
e.g. 35678
Marriage Date
myinfo.marriage_date
Marriage date of the user
string
e.g. 2025-12-04
Divorce Date
myinfo.divorce_date
Divorce date of the user
string
e.g. 2025-12-04
Children Birth Records
myinfo.children_birth_records
For Singaporean citizens and Permanent Residents only.
string
(stringified array of objects with the following attributes:
- birth_cert_no
- name
- date_of_birth
- sex
- race
- life_status
- secondary_race
- vaccination_requirements
- is_sg_citizen_at_birth
)
e.g. []
or [{"birth_cert_no":"T1808765G", "name":"ABC", "date_of_birth":"2018-04-13","sex":"FEMALE","race":"CHINESE","life_status":"ALIVE","secondary_race":"MALAY","vaccination_requirements":[{"fulfilled":"TRUE","requirement":"Preschool Admission Vaccination Min Requirement Fulfilled"}],"is_sg_citizen_at_birth":"Y"}]
Sponsored Children Records
myinfo.sponsored_children_records
For Singaporean citizens, Permanent Residents, and Long Term Visit Pass holders only.
string
(stringified array of objects with the following attributes:
- nric
- name
- date_of_birth
- sex
- race
- life_status
- nationality
- residential_status
- secondary_race
)
e.g []
or [{"nric":"T1872646C","name":"ABC","date_of_birth":"2018-05-05","sex":"MALE","race":"MALAY","life_status":"ALIVE","nationality":"BRITISH OVERSEAS TERRITORIES CITIZEN","residential_status":"PR","secondary_race":"EURASIAN"}]
Last four characters of NRIC
myinfo.nric_last_four_characters
The last 4 characters of an individual's NRIC / FIN. Derived from the myinfo.nric_number field.
string
e.g. *****123A
Age above 18 years old
myinfo.is_age_above_18
Indicates whether the individual is 18 years of age or older. Derived from the myinfo.date_of_birth field.
string
(enum: true and false)
e.g. true
Age above 21 years old
myinfo.is_age_above_21
Indicates whether the individual is 21 years of age or older. Derived from the myinfo.date_of_birth field.
string
(enum: true and false)
e.g. true
Public Officer Employment Details
pocdex.public_officer_details
List of public officer employments.
string
(stringified array of objects with the following attributes:
- work_email
- agency_name
- department_name
- employment_type
- employment_title
)
e.g. []
or
Number of Public Officer Employments
pocdex.number_of_employments
Number of public officer employments.
string
(to be casted as number
)
e.g. 1
Create an sgID authorization URL to redirect your user to so that they can authenticate with Singpass
Must be set to code
because sgID only supports the authorization code flow
code
sgID client ID which was provided to you during client registration
MYCLIENT-PROD
The callback URL that was provided during registration. sgID redirects to this URL with the authorization code after the user authenticates with Singpass
https://example.com/callback
A URL-encoded string of the scopes your client will request for
openid%20myinfo.name%20myinfo.passport_expiry_date%20myinfo.nric_number
Randomly generated string to be returned in the ID token. Used to prevent replay attacks as part of the OpenID Connect 1.0 spec
BQO8SV3ALIYA808IZ8O7PKWRI8A8X6MI
A unique and non-guessable value associated with each authentication request about to be initiated. Used to prevent CSRF attacks and to maintain state as part of the OAuth 2.0 spec (RECOMMENDED)
tk39drykro3
The method used to verify the code challenge. Throws an error response if the value is not 'S256'
S256
A SHA256 hashed string that should be used to verify against the code verifier in the token request
CUZX5qE8Wvye6kS_SasIsa8MMxacJftmWdsIA_iKp3I
Exchange auth code for access token as part of sgID authorization code flow
sgID client ID which was provided to you during client registration
sgID client secret which was provided to you during client registration
Authorization code that was received from the callback URL after the user authenticates with Singpass
This field must take the value authorization_code
as sgID only supports the OAuth 2.0 authorization code flow
A cryptographically random string that was used to generate your code challenge in the authorization request