Node.js

Integrating with JavaScript and TypeScript applications

This page provides an overview of how the SDK should be used in the OIDC flow.

If you are less familiar with OIDC and are unsure how our SDK would fit into the flow, please refer to our step-by-step example guides to learn how to integrate sgID

Install the SDK

npm i @opengovsg/sgid-client

Initialize the SDK

import { SgidClient } from '@opengovsg/sgid-client'

// Replace the values below with your own client credentials
const sgidClient = new SgidClient({
  clientId: 'CLIENT-ID',
  clientSecret: 'cLiEnTsEcReT',
  privateKey: '-----BEGIN PRIVATE KEY-----MII ... XXX-----END PRIVATE KEY-----',
  redirectUri: 'http://localhost:3000/callback',
})

Integrate with sgID using the SDK

When a user tries to login on your application with sgID, you need to:

Step 1: Generate a PKCE pair

Proof Key for Code Exchange (PKCE) is an OAuth 2.0 enhancement to protect against certain attacks and is mandatory for sgID.

import { generatePkcePair } from "@opengovsg/sgid-client"

const { codeVerifier, codeChallenge } = generatePkcePair();

Each PKCE pair must be unique for each authorization request.

Step 2: Create an authorization URL to redirect to

To allow your user to login into your app with sgID, you need to create an sgID authorization URL to redirect your user to so that they can authenticate with Singpass.

// Note: replace the function arguments with your own client data
const { url } = sgidClient.authorizationUrl({
  // Required params
  codeChallenge: codeChallenge // generated from the previous step
  
  // Optional params
  scope: ['openid', 'myinfo.name'], // or space-concatenated string
  redirectUri: 'http://localhost:3000/callback', // overrides redirect uri provided in constructor
  nonce: null, // defaults to randomly generated nonce if unspecified
  state: 'state', // no longer mandatory as PKCE protects against CSRF
})

A sample full authorization URL should look something like this:

https://id.sgid.com/v2/oauth/authorize?client_id=mockClientId&scope=myinfo.name%20openid&response_type=code&redirect_uri=https%3A%2F%2Fsgid.com%2Fcallback&nonce=mh7i-y5h_hCGz-y-v_EyIIPl7BosDNBSEOs46-hBYC4&state=mockState&code_challenge=mockCodeChallenge&code_challenge_method=S256

https://api.id.gov.sg/v2/oauth/authorize?
    response_type=code
    &client_id=abc
    &scope=openid%20myinfo.name%20myinfo.passport_expiry_date%20myinfo.nric_number
    &redirect_uri=http://localhost:3000/callback
    &nonce=BQO8SV3ALIYA808IZ8O7PKWRI8A8X6MI
    &state=tk39drykro3
    &code_challenge=zaqUHoBV3rnhBF2g0Gkz1qkpEZXHqi2OrPK1DqRi-Lk
    &code_challenge_method=S256

Step 3: Exchange auth code for access token and ID token

After the user authenticates with Singpass, sgID will redirect the user back to the callback URL you provided, together with the authorization code. Reusing the callback URL defined in the example above:

http://localhost:3000/callback?
    code=someauthcode

Using this authorization code, we can use the SDK to exchange it for an access token, which will be used to retrieve user information.

const { sub, accessToken } = await client.callback({
  // Required params
  code: 'someauthcode', // auth code reuturned from redirect_url
  codeVerifier: codeVerifier, // generated from step 1
  
  // Optional params
  nonce: null,
  redirectUri: 'http://localhost:3000/callback', // if you overrode the redirect uri when constructing the authorization url
});

Here, the sub refers to the end user's unique identifier for your client. Note that as part of sgID's privacy-preserving measures, each end user's unique identifier is different for each sgID client.

Step 4: Request for user info with access token

Once you have the access token, you can use it to request information about the user corresponding to the scopes that you requested.

const { sub, data } = await client.userinfo('access_token');
// data: { myinfo.nric_number: "S1231231A", myinfo.name: "JAMUS TAN" }

Last updated