Singpass IdP

What is Singpass?

Singpass is an IdP that is part of the Singaporean Government's National Digital Identity (NDI) Initiative, providing better convenience and security for Singaporean users when transacting online. By using Singpass, details can be transacted securely to the public and private sectors.

Singpass is a critical part of identity verification, making this process straightforward and simple. It is used to quickly identify an individual, allowing for a single action by the users to provide the required personal data. Users would need to provide explicit consent to provide their details.

📘

Link-Up Submission

To be able to connect to Singpass, it is necessary to submit the expected user journey and captured data points for approval by Singpass via Assurity on the Singpass API Dev portal.

This submission is necessary when the following occur:

  • Creating a new user journey
  • Modifying an existing journey
  • Capturing a new data set
  • Modifying an existing data set

It is crucial this approval process is performed early, as this process will take at least 2 weeks to be processed. Please refer to Reference Journey for more info.

Data attributes

As part of the LinkUp application, you need to apply for the individual data attributes you're looking for. For eKYC requirements in Singapore, we strongly recommend applying for the following attributes at minimum:

- uinfin
- name
- aliasname
- hanyupinyinname
- hanyupinyinaliasname
- residentialstatus
- nationality
- dob
- regadd
- email
- mobileno
- passportnumber
- passportexpirydate
- passtype
- passstatus
- passexpirydate

OneSDK Federation flow

As an initial proof of concept, we integrated with Singpass through MyInfo API. It's based on OAuth2 flow to perform authorisation & authentication.

Overview of MyInfo/ Singpass Integration  
Ref: [Singpass API](https://api.singpass.gov.sg/library/myinfo/developers/overview)

Overview of MyInfo/ Singpass Integration
Ref: Singpass API

Since the OAuth2 flow is implemented with two browser redirects, we split the end-to-end flow into two parts: Authorisation and Approval. All the details described below are handled by OneSDK internally and you may skip directly to the Getting started section.

1 - Authorisation

The Authorisation is handled at the frontend with a simple redirect to the authorisation page, whose URL is taken from a pre-defined configuration. The redirect includes some extra parameters:

  • client_id, pre-configured Singpass application id. Provided with the configuration.
  • attributes, list of Singpass user attributes. It needs to match the pre-configured list of attributes. Provided with the configuration.
  • state, session id generated by BFF when the current OneSDK session was created and can be extracted from the session token itself (JWT). This is a requirement and guarantees the data is authorised and retrieved by the same agent.
  • redirect_uri, the url to redirect the browser after Authorisation is confirmed. Provided with the configuration.
  • purpose some hard-coded value required by Singpass. Provided with the configuration.

🚧

Callback (redirect) URL

The OAuth2 flow is based on the callback mechanism, so the client application needs to initialise OneSDK component in two separate instances, initially before the redirect and after returning to the callback page.

The configured callback url may be the same page as the initial page.

Flow:

  1. The application’s backend generates a session with BFF, which returns a token containing a session id.
  2. The OneSDK is initialised using that token.
  3. The OneSDK uses the token to fetch the corresponding Customer Recipe configuration.
  4. The application initialises the OneSDK Federation component which will store the current token in the browser's temporary Session Storage (similar to LocalStorage).
  5. The application then calls the start method, which detects the configuration for Singpass IdP and starts the Singpass wrapper.
  6. The Singpass wrapper will then use the loaded Recipe configuration to appropriately redirect the browser to the Singpass Login/Authorisation page.
  7. Once the user successfully logs in and authorises the flow, Singpass will return the browser to the configured redirect_uri (aka the callback url) with the authorisation code included as a url parameter.
  8. The page sitting in the callback url will again initialise both the OneSDK (using a new/unrelated token) and the Federation component, which will in turn reuse the same token stored in the temporary storage.
  9. The same page will again call the start method, which will
    1. initialise the Singpass Wrapper internally
    2. detect the authorisation code in the url
    3. submit the authorisation code to BFF with the reused token, instead of the new provided token
  10. BFF will connect to Singpass/MyInfo to exchange the authorisation code with an access token.
  11. With the access token, BFF will connect to Singpass/MyInfo again to retrieve the Individual’s information. BFF will then cache the data and return it to OneSDK.

As seen above, the authorisation flow requires some static configuration. That configuration will be handled by FrankieOne internally so the OneSDK's initialisation is as simple as possible.

2 - Approval

The Approval flow is when the Individual information is successfully retrieved. If everything goes as expected, a results event is emitted that contains the Individual data, a status and an approve callback.

The approve callback should be called when the user confirms the information at the frontend. Once it is called, a request will be sent to BFF to import the cached Individual's data and create an entity in FrankieOne platform. The cached data expires after 30 mins by default, so if the user doesn't approve within this time, you will get an error after.

For more information on how the pre-verified data will be imported to FrankieOne platform, please refer to import past kyc check data.

Getting started

As mentioned above, the Federation flow is split into two parts, where the OneSDK needs to be initialised separately. The steps are the same for both parts:

  1. create an instance of the OneSDK
  2. create an instance of the Federation component
  3. listen to the results and error events
  4. call the Federation component's method "start".

Error payloads will be described later.

// 1
const oneSDK = await OneSdk({ session });

// 2
const federationComponent = oneSDK.component("federation");

// 3
federationComponent.on("error", ({ message, payload }) => {
   console.log(message, payload);
});

// The results event will only be triggered in the Callback page and may be skipped initially
federationComponent.on("results", (individual, status, approve) => {
  showIndividualForApproval(individual);
  approve();
});

// 4
federationComponent.start();

For now, the value of the second parameter "status" in the "results" event should be ignored as it might still change. Whenever the results event is fired, individual is always expected to have data.

Sample HTML code

Here is a sample HTML code running on the OneSDK RC branch and using the Singpass sandbox environment.

<html lang="en">
  <head> </head>
  <title>oneSdk onboarding</title>
   <script src="https://assets.dev.frankiefinancial.io/one-sdk/RC/oneSdk.umd.js"></script>
  <script>
let federationComponent;
async function startOneSdk() {
    const sessionObjectFromBackend = { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7Im9yZ2FuaX..."};

    const oneSdk = await OneSdk({
        session: sessionObjectFromBackend,
    });

    federationComponent = oneSdk.component("federation");
   
}

function startFederation() {
    if (!federationComponent) alert("Federation not initialised yet");

    federationComponent.on("results", async (individual, status, approve) => {

        console.log(individual);
        await approve();

    });

    federationComponent.on("error", ({ message, payload }) => {
      console.log(message);
    });

    federationComponent.start();

}

</script>
</head>
<body style="background-color: blue" onload="startOneSdk()">
    <button onclick="startFederation">Sign up with Singpass</button>
</body>