MyInfo API (4.0.7)

Download OpenAPI specification:Download

MyInfo REST APIs for retrieving Person data.

Note - this specification is subject to changes based on evolution of the APIs.

Release Notes

  • 4.0.7 (15 Apr 2025)

    • Data Items
      • New:
        • chas (Only on Singpass)
      • Updated:
        • vehicle enginecapacity field: Allow 0 for electric vehicle (EV)
  • 4.0.6 (18 Mar 2025)

    • Data Items
      • Updated:
        • drivinglicence pdl classes field: Updated max length to 3 characters
        • drivinglicence qdl classes field: Updated max length to 3 characters
  • 4.0.5 (17 Jan 2025)

    • Data Items
      • Updated:
        • cpfcontributions employer name field: Updated max length to 100 characters
        • cpfemployers employer name field: Updated max length to 100 characters
  • 4.0.4 (29 Dec 2023)

    • Data Items
      • Updated:
        • regadd building field: Updated max length to 65 characters
  • 4.0.3 (02 Aug 2023)

    • Updated URL for the RFC containing date information
    • Updated overview and sequence diagrams
  • 4.0.2 (31 Jul 2023)

    • Operation
      • Updated:
        • Scheduled downtime
    • Data Items
      • New:
        • ltavocationallicences.tdvl.licencename
        • ltavocationallicences.tdvl.vocationallicencenumber
        • ltavocationallicences.tdvl.expirydate
        • ltavocationallicences.tdvl.status
        • ltavocationallicences.pdvl.licencename
        • ltavocationallicences.pdvl.vocationallicencenumber
        • ltavocationallicences.pdvl.expirydate
        • ltavocationallicences.pdvl.status
        • ltavocationallicences.bdvl.licencename
        • ltavocationallicences.bdvl.vocationallicencenumber
        • ltavocationallicences.bdvl.expirydate
        • ltavocationallicences.bdvl.status
        • ltavocationallicences.bavl.licencename
        • ltavocationallicences.bavl.vocationallicencenumber
        • ltavocationallicences.bavl.expirydate
        • ltavocationallicences.bavl.status
        • ltavocationallicences.odvl.licencename
        • ltavocationallicences.odvl.vocationallicencenumber
        • ltavocationallicences.odvl.expirydate
        • ltavocationallicences.odvl.status
      • Updated:
        • cpfinvestmentscheme scope updated to be retrieved by individual fields
        • cpfinvestmentscheme.account
        • cpfinvestmentscheme.saqparticipationstatus
        • cpfinvestmentscheme.sdsnetshareholdingqty
  • 4.0.1 (31 Mar 2023)

    • Data Items
      • Updated:
        • cpfcontributions.history employer field: Corrected max length to 30 characters
        • cpfemployers.history employer field: Corrected max length to 30 characters
  • 4.0.0 (3 Nov 2022)

    • Security
    • APIs
      • Test:
        • /com/v4/authorize
        • /com/v4/token
        • /com/v4/person/{sub}/
        • /com/v4/person-sample/{uinfin}/
      • Production:
        • /com/v4/authorize
        • /com/v4/token
        • /com/v4/person/{sub}/
      • Updated:
        • /Authorize
          • Updated /authorise to /authorize to conform to standards
          • Updated 'purpose' to 'purpose_id'
          • Renamed parameter 'attributes' to 'scope' to conform to standards
          • Updated scope to be space(' ') separated to conform to standards
          • Removed 'authmode' parameter
          • Removed 'login_type' parameter
          • Removed 'state' parameter
          • Added mandatory field code_challenge
          • Added mandatory field code_challenge_method (Only supports S256)
        • /Token
          • Removed Authorization field in HTTP header
          • Added mandatory field DPoP in HTTP header
          • Removed state field in body
          • Added mandatory client_assertion field in body
          • Added mandatory client_assertion_type in body
          • Added mandatory code_verifier field in body
        • /Person
          • Removed 'txnNo' parameter
          • Removed 'client_id' parameter
          • Added 'iat' (issue at) and 'txnid' (transaction id) in JWS response from /person.
          • Renamed parameter 'attributes' to 'scope' to conform to standards
          • Scope is updated to be space(' ') separated to conform to standards
          • Updated Authorization field prefix from bearer to DPoP in HTTP header
          • Added mandatory field DPoP in HTTP header
    • Data Items
      • Updated:
        • cpfbalances
          • Updated data structure for each nested data item (i.e. cpfbalances.oa, cpfbalances.ma, cpfbalances.sa, cpfbalances.ra) to have its own set of 'classification', 'source' and 'lastupdated' fields
          • cpfbalances.ra will appear with 'unavailable' flag set to 'true' if user does not have a Retirement Account
      • New:
        • childrenbirthrecords.sgcitizenatbirthind
        • cpfmonthlypayouts
        • cpfrstuselftopupamount
        • cpfrstucurrentyeartaxrelief
        • cpflife
        • cpfmedishieldlife
        • cpfbalances.oa
        • cpfbalances.sa
        • cpfbalances.ma
        • cpfbalances.ra
      • Removed:
        • vehno
        • workpassstatus
        • workpassexpirydate
        • mailadd
        • billadd
        • homeno
        • edulevel
        • gradyear
        • schoolname
        • householdincome
  • 3.2.7 (26 Jan 2023)

    • Data Items
      • Updated:
        • sponsoredchildrenrecords updated to include LTVP
  • 3.2.6 (20 Dec 2022)

    • Removed backchannel authentication.
  • 3.2.5 (22 Nov 2022)

    • Data Items
      • Updated:
        • Corrected attribute name from cpfdependentprotectionscheme to cpfdependantprotectionscheme
  • 3.2.4 (3 Nov 2022)

    • Data Items
      • Updated:
        • Description of 'Nationality' updated to 'Nationality/Citizenship'
        • Description of Country updated to 'Country/Place'
    • Operation
      • Updated:
        • Downtime
  • 3.2.3 (22 July 2022)

    • Data Items
      • Updated:
        • cpfhomeprotectionscheme: Corrected attribute response structure
        • cpfdependentprotectionscheme: Corrected attribute response structure
  • 3.2.2 (26 May 2022)

    • Data Items
      • New:
        • cpfinvestmentscheme
        • childrenbirthrecords.vaccinationrequirements
        • sponsoredchildrenrecords.vaccinationrequirements
        • hdbownership.purchaseprice
        • hdbownership.outstandinginstalment
      • Updated:
        • Description of lastupdated to indicate that value may be blank if source agency does not have record for the user
  • 3.2.1 (10 Feb 2022)

    • Data Items
      • New:
        • merdekagen
        • pioneergen
        • cpfhomeprotectionscheme
        • cpfdependentprotectionscheme
      • Updated:
        • regadd updated to include FIN registered address, which may also be unavailable.
  • 3.2.0 (11 May 2021)

    • Data Items
      • New:
        • partialuinfin
        • academicqualifications
        • cpfhousingwithdrawal
      • Deprecated:
        • mailadd
        • billadd
        • homeno
        • edulevel
        • gradyear
        • schoolname
        • householdincome
      • Updated:
        • Type enum for regadd (Unformatted to UNFORMATTED)
        • Description of SG Address Block to 'Block/House of Address'
        • Description for cpfcontributions to maximum of 15 months records
        • marriagecertno to maximum 50 characters
        • Local phone number default to '65'
        • Employment Sectors of workpass to upper case, remove enumeration and provide examples of possible values
        • Value of dob updated to include potential formats 'YYYY' and 'YYYY-MM'
        • Removed code and desc fields from 'occupation' as these are SC/PR user provided fields. For FIN user's occupation, continue to use 'occupation.value'
    • Security
      • Certificate Authority list
        • Comodo to Comodo/Sectigo
        • New CA: Netrust
      • Network
        • Updated TLS version to only 1.2
        • Updated recommended cipher suites
    • Features
      • Added 'appLaunchURL' request parameter in 'Authorise' API for launching mobile application after successful authentication using SingPass mobile
  • 3.1.1 (4 December 2019)

    • Updated path parameter 'uinfin' of person API to 'sub', indicating that the value of this parameter should come from the 'sub' attribute in access_token.
    • Updated sample code 'createPersonRequest' function under person API to use 'sub' instead of 'uinfin'.
  • 3.1.0 (16 September 2019)

    • New data items available:
      • cpfemployers
      • partialuinfin
    • New 'subentity' parameter in person API that allows traceability to platform's client who will be receiving the person data.
    • Provide clarity on the handling of housingtype & hdbtype
  • 3.0.2 (10 May 2019)

    • Upper case all desc values for:
      • Driving Licence : Comstatus, PDL and QDL Validity
      • Children Birth Records: Sex
      • Sponsored Children Records: Sex, Residential Status
      • Person: Sex, Residential Status
  • 3.0.0 (31 Mar 2019)

    IMPORTANT NOTE: response format for person API has substantial changes from the previous version. Please refer to Understanding the Data Structure for details.

    • APIs updated to v3:
      • Test:
        • /com/v3/authorise
        • /com/v3/token
        • /com/v3/person/{uinfin}/
        • /com/v3/person-sample/{uinfin}/
      • Production:
        • /com/v3/authorise
        • /com/v3/token
        • /com/v3/person/{uinfin}/
    • Response changes from JWE to JWE wrapping JWS
    • Security header (changes in Authorization header parameters)
      • Streamline header parameters to app_id, nonce, signature_method (RS256), signature, timestamp
    • Standardisation of 'code', 'desc' and 'value' of all data items.
    • New data items available:
      • employmentsector
      • passtype
      • hdbownership
      • sponsoredchildrenrecords
      • vehicles
      • drivinglicence
    • Rename data items:
      • workpassstatus -> passstatus
      • workpassexpirydate -> passexpirydate
    • Changes to the following data item to include "type" discriminator to discriminate local and foreign address. Format is significantly different between the two.
      • regadd
      • billadd
      • mailadd
    • Deprecated vehno attribute
    • Updated scheduled downtimes: sandbox and test enviroments will no longer have any scheduled downtimes.

Releases and Compatibility

The RESTful API adopts Semantic Versioning 2.0.0 for releases, and every new release of the API increments the version numbers in the following format:

{MAJOR}.{MINOR}.{PATCH}
  1. {MAJOR} number introduces incompatible API changes with previous {MAJOR} number also resets {MINOR} to 0,
  2. {MINOR} number introduces new functionalities or information that are backward compatible also resets {PATCH} to 0, and
  3. {PATCH} number introduces bug fixes and remains backward compatible.

Pre-release or draft versions, when provided, are denoted by appended hypen - with a series of separate identifiers {LABEL}-{VERSION} following the {PATCH} number. Such releases are unstable and may not provide the intended compatibility with the specification in draft status.

Serving as notice, the RESTful API in version 2.X.X are incompatible with version 1.X.X releases.

Despite backward compatibility in {MINOR} or {PATCH} releases, API consumers are best to evaluate and determine their implementation does not disrupt use-case requirements.

Overview

The following diagram illustrates how the integration with MyInfo APIs work: Overview

As shown above, partner's application will be interfacing with Myinfo's API Gateway to integrate successfully with MyInfo.

Environments

The RESTful APIs are provided in both testing and live environments, and are accessible over the Internet via HTTPS.

Consumers are to ensure firewall clearance on their edge network nodes for connecting to the APIs.

The convention used by API endpoints' URLs is in the following format:

https://{ENV_DOMAIN_NAME}/{CONTEXT}/{VERSION}/{RESOURCE}
  • {ENV_DOMAIN_NAME} indicates MyInfo's API domain names - respectively:

    • sandbox.api.myinfo.gov.sg, or
    • test.api.myinfo.gov.sg, or
    • api.myinfo.gov.sg, following
  • /{CONTEXT}, indicates the context of the API call = /com

  • /{VERSION} indicates the endpoint's release {MAJOR} version number path - for this release = /v4

  • /{RESOURCE} indicates the API resource path name. Any additional query string parameters are appended as needed.

Available Environments

1. Test Environment

The test enviroment is used for testing partner's application with the full security measures required in production. The Person API will return test data described in https://api.singpass.gov.sg/library/myinfo/developers/resources-personas.

Note:

  • Domain Name: test.api.myinfo.gov.sg
  • Client assertion, DPoP Proof JWT and PKCE are required in Token API.
  • Authorization DPoP-bound access token and DPoP Proof JWT are required in Person API.
  • Authorization DPoP-bound access token should be verified by partner's application.

2. Production Environment

The production enviroment is the actual live environment with full security measures and live data.

Note:

  • Domain Name: api.myinfo.gov.sg
  • Client assertion, DPoP Proof JWT and PKCE are required in Token API.
  • Authorization DPoP-bound access token and DPoP Proof JWT are required in Person API.
  • Authorization DPoP-bound access token should be verified by partner's application.

Scheduled Downtimes

The following are the scheduled downtimes for the various environments:

Production Environment

  • CPFB data

    • Every day 0500hrs to 0530hrs
    • Every 1st Sun of the month from 0000hrs to 0800hrs
    • Every 4th Sun of the month from 0000hrs to 0800hrs
  • IRAS data

    • Every Wed, 0200hrs to 0600hrs
    • Every Sun, 0200hrs to 0830hrs
  • MOM data

    • Every 4th Sun of the month from 0000hrs to 0600hrs

Test Environment

  • none

Security

Enhancements in v4

API Security

PKCE (V4)

PKCE is introduced to protect against authcode injection attacks by requiring partners to prove to the authorization server that the authcode belongs to them in order for the authorization server to issue access token. This is achieved by code challenges and code verifiers exchanged during the /authorize and /token call respectively.

PKCE replaces the use of 'state' parameter. Partners are required to manage a session to their frontend to link the code_verifier and code_challenge.

Client Verification

JWKS(V4) vs Certificate(V3)

Instead of relying on certificates uploaded during onboarding, partners will now need to specify their respective JWKS (JSON Web Key Set) URLs in order for /token call to retrieve the partner's public_signing_key used to verify client assertions signatures and for /person call to retrieve the partner's public encryption key used to encrypt the data.

Sample JWKS:

{
  "keys": [
      {
          "use": "sig",
          "alg": "ES256",
          "kty": "EC",
          "kid": "vPT7o62ke_t4dTUQQwDhcFw_hX_FbiwFS3eCvYC2yz8",
          "crv": "P-256",
          "x": "jbqsZUCAf_Sj1oq6jR0ErpzIGbiAJ_GgHkZ18YeOgGE",
          "y": "xB2rsB3a8xug6eiacWrxoTNJi92hyO1eNccpKBGjqdo"
      },
      {
          "use": "enc",
          "alg": "ECDH-ES+A256KW",
          "kty": "EC",
          "kid": "iop1ls7rt-Y1jmFXTWsxxb3TKKgxwB566V2pUVJdjVY",
          "crv": "P-256",
          "x": "bqYdlztg_OhQt2a-ocr05Feu6nHXFVZ2oy7R750t3TA",
          "y": "Suu4cYvK0rH6njN_1Q2utIYrEffDYCtzFyxdcI2nrfM"
      }
  ]
}

This approach allows partners to manage keys autonomously and enables minimal disruption during key rotation (JWKS holding multiple keys at the same time). Myinfo has similarly introduced JWKS endpoints to distribute our public signing keys for partners to perform signature verification. This will enable minimal disruption for partners during Myinfo's key rotation.

For performance reasons, NDI caches the keys found in the partners' JWKS endpoint for one hour. When partners' signing keys need to be rotated, new keypairs must use different key id (kid) values and maintain both old and new keys in the JWKS for at least an hour.

Client Assertion(V4) vs Base String Signing(V3)

Taking reference from RFC7251, Client Verification in v4 relies on Client Assertion as opposed to checking signature of a formulated Base String. Though the verification mechanism remains unchanged i.e. checking of digital signature, Client Assertion is more aligned to international standards.

Together with the Client Assertion, partners will need to provide a DPoP Proof JWT in the HTTP header with an ephemeral public signing key, which is used in the /person call for verification of access token possession.

DPoP(V4) vs Base String Signing(V3)

During /person call, partners will need to generate DPoP Proof JWT that correspond to the access tokens received to prove legitimacy of possession before data can be released. The DPoP token will be signed using the partner's ephemeral private signing key and Myinfo will check using the partner's ephemeral public signing key provided previously in the /Token call.

HTTPS Interface

MyInfo's API gateway supports accessing of APIs via the following interfaces:

  • HTTP version 1.1 connection over TLS (Transport Layer Security) version 1.2 standards, and cipher suites:

    • using AES (Advanced Encryption Standard) and SHA (Secure Hash Algorithm),
    • on either GCM (Galois/Counter Mode) or CBC (Cipher Block Chaining) mode.
  • Below is the list of recommended cipher suites that partners may use:

    • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
    • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

IMPORTANT: ensure partner's server supports TLS 1.2 and supports a cipher suite in the list above.

Accessing the RESTful APIs using prior versions of TLS and/or unsupported ciphersuites will result in connectivity errors. MyInfo's API gateway does not support 2-way TLS client nor mutual authentication.

API HTTP interface features:

  1. JSON (JavaScript Object Notation) is the supported data media format and indicated in Content-Type header application/json, also
  2. Content-Length header is omitted by having Transfer-Encoding header chunked emitted for streaming data, and
  3. GZip (GNU Zip) response compression is supported by opt-in Accept-Encoding: gzip and indicated in Content-Encoding header gzip.

OAuth2.1

MyInfo APIs use OAuth2.1 authorisation code flow to perform authentication & authorisation.

The sequence diagram below illustrates the steps involved in integrating partner's application with Myinfo APIs:

OAuth

The flow consists of 3 APIs:

  1. Authorise

    • This will trigger the SingPass login and consent page. Once successful, partner's application will receive the authorisation code via partner's callback url.
  2. Token

    • Call this server-to-server API with a valid authorisation code to get the access token.
  3. Protected Resource (Person)

    • Call this server-to-server API with a valid access token to get the person data.

Proof Key for Code Exchange (PKCE)

PKCE is an extension to the Authorization Code flow to prevent CSRF and authorization code injection attacks (Refer to https://datatracker.ietf.org/doc/html/rfc7636). The mechanism relies on 2 parameters namely code_challenge (base64(sha256(code_verifier))) and code_verifier (cryptograhic random string generated and kept secret on serverside) sent in the authorize and token call respectively to enable the Authorisation Server to perform correlation. Below is an example of how code_verifier and code_challenge are produced on server side. The code_challenge can then be attached to the authorize call.

Sample Code in NodeJS

function base64URLEncode(str) {
  return str.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
}
function sha256(buffer) {
  return crypto.createHash('sha256').update(buffer).digest();
}
function generateCodeChallenge(codeVerifier) {
  try {
    let codeChallenge = base64URLEncode(sha256(codeVerifier));
    return codeChallenge;
  } catch (error) {
    // error handling
    throw (error);
  }
}
var codeVerifier = base64URLEncode(crypto.randomBytes(32)); var codeChallenge = generateCodeChallenge(codeVerifier);

Authentication methods provided by Myinfo on internet:

  • OAuth 2.1 using Client Assertion (see "Client Assertion" section below)
  • Client Assertion should be signed using a key that is published on partner's JWKS endpoint, which is submitted during client onboarding.

Client Assertion

The Partner's application is required to generate client assertions to be attached to server-to-server calls to prove authenticity (Refer to https://datatracker.ietf.org/doc/html/rfc7521). The partner's private key signs the assertion metadata, and Myinfo will use the partner's onboarded JWKS endpoint to obtain the public key for verification.

Below is a sample of the JWT header and payload of the client assertion:

{
  "typ": "JWT",
  "alg": "ES256",
  "kid": "x0zDLIC9yNRIXu3gW8nTQDOMNe7sKMAjQnZj3AWTW2U",
} . {
  "sub": "PROD2-MYINFO-SELF-TEST",
  "jti": "jNDZuyLw66gkTjmCNMawzrTJNlhS8wdjpU0DHTzo",
  "aud": "https://api.myinfo.gov.sg/com/v4/token",
  "iss": "PROD2-MYINFO-SELF-TEST",
  "iat": 1662365106,
  "exp": 1662365406,
  "cnf":{
    "jkt": "G_q8Qv9-xv_9xJo-esolTnvxVSobMER7O0LKGPBlTqY"
  }
}
  • {sub} Subject - client_id issued by Myinfo upon onboarding
  • {jti} JWT ID - random unique identifier
  • {aud} Audience - URL that partner's application is calling
  • {iss} Issuer - client_id issued by Myinfo upon onboarding
  • {iat} Issued At - current timestamp
  • {exp} Expiry - expiry timestamp, maximum 300 seconds (5 minutes)
  • {cnf.jkt} JWK Thumbprint - base64url encoding of the JWK SHA-256 Thumbprint of the partners's ephemeral public signing key used to sign the DPoP Proof JWT

Sample post body with DPoP Proof and client assertion

Below is an example of a post body of a token API call:


  // Response body of token call in a transaction

  POST /token HTTP/1.1
  Host: api.myinfo.gov.sg
  Content-Type: application/x-www-form-urlencoded
  DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImp3ayI6eyJrdHkiOiJFQyIsImtpZCI6IkdfcThRdjkteHZfOXhKby1lc29sVG52eFZTb2JNRVI3TzBMS0dQQmxUcVkiLCJjcnYiOiJQLTI1NiIsIngiOiJPMTRHMXVlUjBTeHRSNGRsVW9rZ1FzMmM3NXFLV1VXSVRLWDYwaXYwTHkwIiwieSI6IlMzQjhSUC1OaGc2dTBMTE43Y0ZfX2lzUmctQVNHcFp3WTN4V2JrQVFRWXMiLCJ1c2UiOiJzaWciLCJhbGciOiJFUzI1NiJ9LCJhbGciOiJFUzI1NiJ9.eyJodHUiOiJodHRwczovL3NpdC5hcGkubXlpbmZvLmdvdi5zZy9jb20vdjQvdG9rZW4iLCJodG0iOiJQT1NUIiwianRpIjoib3MyWk14cEZVMnpISm9aTWhXbkFaeWRwcWYyM0JsZ3dDTkFFcmptRyIsImlhdCI6MTY2MjM2NTEwNiwiZXhwIjoxNjYyMzY1MjI2fQ.X69HdF8C_9IRAeDGG9kr7ViV4SGyH7G4ovm_pTlvHwQaLJvr4f4Lf445h-2aPt06kPagnfuO4-HgctRalxThqw

  grant_type=authorization_code&
  code=5uHGo2QpNAG99gO6rjqtzNuzrdnzJwatjpeuejvB&
  redirect_uri=http%3A%2F%2Fmyapp.com%2Fcallback&
  client_id=STG2-MYINFO-SELF-TEST&
  code_verifier=ZK2mVhN9gBY9aGytuTIYmU7yHMueb7jZxMrE4WzjRRU&
  client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&
  client_assertion=eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6ImFRUHlaNzJOTTA0M0U0S0Vpb2FIV3ppeHQwb3dWOTlnQzlrUkszODhXb1EifQ.eyJzdWIiOiJTVEcyLU1ZSU5GTy1TRUxGLVRFU1QiLCJqdGkiOiJqTkRadXlMdzY2Z2tUam1DTk1hd3pyVEpObGhTOHdkanBVMERIVHpvIiwiYXVkIjoiaHR0cHM6Ly9zaXQuYXBpLm15aW5mby5nb3Yuc2cvY29tL3Y0L3Rva2VuIiwiaXNzIjoiU1RHMi1NWUlORk8tU0VMRi1URVNUIiwiaWF0IjoxNjYyMzY1MTA2LCJleHAiOjE2NjIzNjU0MDYsImNuZiI6eyJqa3QiOiJHX3E4UXY5LXh2Xzl4Sm8tZXNvbFRudnhWU29iTUVSN08wTEtHUEJsVHFZIn19.OuXR4qOmY8Lilqf6QcgC7PW1hRAgWoG41gHdSC4N-6UiipH1kgdXynazq0rF5JxqOi0Bxah4Jh41KbgEoJ3geQ

Sample Code in NodeJS that generates the DPoP Proof and client assertion

async function generateClientAssertion(url, clientId, privateSigningKey, jwkThumbprint){
  try {
    let now = Math.floor((Date.now() / 1000));

    let payload = {
      "sub": clientId,
      "jti": generateRandomString(40),
      "aud": url,
      "iss": clientId,
      "iat": now,
      "exp": now + 300,
      "cnf" : {
        "jkt": jwkThumbprint
      }
    };

    let jwsKey = await jose.JWK.asKey(privateSigningKey, "pem");
    let jwtToken = await jose.JWS.createSign({ "format": 'compact', "fields": { "typ": 'JWT' } }, jwsKey).update(JSON.stringify(payload)).final();
    logger.info("jwtToken", jwtToken);
    return jwtToken;
  } catch (error) {
    logger.error("generateClientAssertion error", error);
    throw constant.ERROR_GENERATE_CLIENT_ASSERTION;
  }
};
async function generateJwkThumbprint(ephemeralPublicKey){
  let jwkKey = await jose.JWK.asKey(ephemeralPublicKey, 'pem');
  let jwkThumbprintBuffer = await jwkKey.thumbprint('SHA-256');
  let jwkThumbprint = jose.util.base64url.encode(jwkThumbprintBuffer, 'utf8');

  return jwkThumbprint;
}
async function generateEphemeralKey() {
  let options = {
    "namedCurve": "P-256",
    "publicKeyEncoding": {
      "type": "spki",
      "format": "pem"
    },
    "privateKeyEncoding": {
      "type": "sec1",
      "format": "pem"
    }
  };

  ephemeralKeyPair = crypto.generateKeyPairSync("ec", options);

  let ephemeralPublicKey = (await jose.JWK.asKey(ephemeralKeyPair.publicKey, "pem")).toJSON();
  ephemeralPublicKey.use = "sig";
  ephemeralPublicKey.alg = "ES256";

  return ephemeralPublicKey;
}

Demonstration of Proof of Possesion (DPoP)

Partner's application is required to generate DPoP Proof JWT to be attached to server-to-server resource calls to prove the legit possession of the access token. (Refer to https://datatracker.ietf.org/doc/html/draft-ietf-oauth-dpop). The token is signed by partner's ephemeral private signing key, which the partner's public signing key had been used in the token call and "embedded" into the access token provided.

Below is a sample of the JWT header and payload of a DPoP token:


  {
    "typ": "dpop+jwt",
    "alg": "ES256",
    "jwk": {
      "kty": "EC",
      "kid": "CRx5jixF8ZLRpxpqguxCwiq0g6b-ACHfQQJT7uiAkio",
      "crv": "P-256",
      "x": "mxVK8wvCaQ8iUJ4AyZr1oK1_ceL_27kgTPISNEcChm4",
      "y": "0P-81zpWvcy6YAPSiV_K4h94wdEdk-RwrhbTL0fkeyc"
    }
  }
  . {
    "jti": "dfgsrtsDFBBgbsB230afktmdFGdgegemmet",
    "htu": "https://api.myinfo.gov.sg/com/v4/person/08939d6c-11c0-4bc9-b2cd-f5fd14369521",
    "htm": "GET",
    "iat": 1645757787,
    "exp": 1645757907,
    "ath": "RyPeyISsEqdR1lsZBv80o0A8eF1Kvxdm_uf1hnLRf9M"
  }

  • {typ} Type - Type (Header), value "dpop+jwt"
  • {alg} Algorithm (Header) - digital signature algorithm identifier as per RFC7518 (Refer to https://datatracker.ietf.org/doc/html/rfc7518). MUST NOT be none or an identifier for a symmetric algorithm (MAC).
  • {jwk} JSON Web Key (Header) - public key chosen by the client. MUST NOT contain the private key.
  • {jti} JWT ID (Payload) - unique identifier
  • {htu} HTTP URL (Payload) - HTTP URI used for the request, without query (?) and fragment parts (#)
  • {htm} HTTP Method (Payload) - HTTP method for the request to which the JWT is attached
  • {iat} Issued At (Payload) - current timestamp
  • {exp} Expiry (Payload) - expiry timestamp
  • {ath} Access token hash (Payload) - The base64url encoded SHA-256 hash of the ASCII encoding of the associated access token's value (Required only for /Person call after DPoP-bound access token is issued)

Sample Code in NodeJS that generates the DPoP token

//function to generate the base64url encoded SHA-256 hash of the ASCII encoding of the accesstoken
function generateAth(accessToken){
  let sha256AccessToken =  crypto.createHash('sha256').update(accessToken).digest();
  let base64URLEncodedHash = sha256AccessToken.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
  return base64URLEncodedHash;
};
// generates DPoP Proof JWT headers for calling **Person** API
async function generateDpopProof  (url, method, sessionPopKeyPair, ath) {
  try {
    let now = Math.floor((Date.now() / 1000));
    let payload = {
      "htu": url,
      "htm": method,
      "jti": generateRandomString(40),
      "iat": now,
      "exp": now + 120,
    };

    //required only for /Person resource call
    if(ath)payload.ath = ath; 

    let privateKey = await jose.JWK.asKey(sessionPopKeyPair.privateKey, "pem");
    let jwk = (await jose.JWK.asKey(sessionPopKeyPair.publicKey, "pem")).toJSON(true);;
    jwk.use = "sig";
    jwk.alg = "ES256";
    let jwtToken = await jose.JWS.createSign({ "format": 'compact', "fields": { "typ": 'dpop+jwt', "jwk": jwk } }, { "key": privateKey, "reference": false }).update(JSON.stringify(payload)).final();
    return jwtToken;
  } catch (error) {
    logger.error("generateDpop error", error);
    throw constant.ERROR_GENERATE_DPOP;
  }
};

Token Validation

NOTE: Person APIs only

Access Tokens are in JWT format. This JWT complies to the standard 'JSON Web Token (JWT) Profile for OAuth 2.1 Client Authentication and Authorization Grants' (https://tools.ietf.org/html/rfc7523). Partner will need to verify the token with Authorise's public signing key in Authorise's JWKS endpoint.

Sample Code in NodeJS

  // Sample Code for Verifying & Decoding JWS or JWT
  async function verifyJWS(compactJWS, JWKSUrl) => {
    var jwks = await getJwks(JWKSUrl);

    try {
      let keyStore = await jose.JWK.asKeyStore(jwks);

      let result = await jose.JWS.createVerify(keyStore).verify(compactJWS);
      let payload = JSON.parse(Buffer.from(result.payload).toString());

      return payload;
    } catch (error) {
      throw "Error with verifying JWS";
    }
  }

Payload Signing and Encryption (Person)

NOTE: Person APIs in Test and Production environments only

The response payload for the Person API (for test and production environments) is first signed, then encrypted:

Encryption protects the data at rest while a signed payload means, if necessary, partner will be able to pass this signed payload to a 3rd party where they can verify the payload's integrity with Myinfo's public signing key in Myinfo's JWKS endpoint.

In order to read the payload, partner has to perform the following steps in order:

  1. Decrypt the payload with the partner's private encryption key corresponding to the partner's encryption public key in the onboarded partner's JWKS endpoint.
  2. Validate the decrypted payload signature with Myinfo's public signing key return from Myinfo's JWKS endpoint.

After doing the above steps, partner's application will be able to extract the payload in JSON format.

STEP 1: Decryption

  • Encryption is done using partner's public encryption key provided in partner's onboarded JWKS endpoint. Decryption of the payload should be using the partner's private encryption key of that key-pair.
  • Current encryption algorithms used:
    • ECDH-ES+A256KW (for content key wrapping)
    • A256GCM (for content encrytion)

Sample Code in NodeJS

  // Sample Code for decrypting JWE
  async function decryptJWEWithKey(compactJWE, encryptionPrivateKey) {
    try {
      let keystore = jose.JWK.createKeyStore();
      let jweParts = compactJWE.split("."); // header.encryptedKey.iv.ciphertext.tag
      if (jweParts.length != 5) {
        throw constant.ERROR_INVALID_DATA_OR_SIGNATURE;
      }

      //Session encryption private key should correspond to the session encryption public key passed in to client assertion
      let key = await keystore.add(encryptionPrivateKey, "pem");

      let data = {
        "type": "compact",
        "protected": jweParts[0],
        "encrypted_key": jweParts[1],
        "iv": jweParts[2],
        "ciphertext": jweParts[3],
        "tag": jweParts[4],
        "header": JSON.parse(jose.util.base64url.decode(jweParts[0]).toString())
      };

      let result = await jose.JWE.createDecrypt(key).decrypt(data);

      return result.payload.toString();
    } catch (error) {
      throw constant.ERROR_DECRYPT_JWE;
    }
  };

STEP 2: Verification of Signature

The decrypted payload is signed according to JWS (JSON Web Signature) format, similar to the access token.

  • signature algorithm used is ES256.
  • Additional attributes 'iat' (epoch time when the signature is generated) and 'txnid' (unique transaction ID for reconciliation purpose) are included in the JWS header.

Sample Code in NodeJS

  // Sample Code for Verifying & Decoding JWS or JWT
  function verifyJWS = async (compactJWS, JWKSUrl) => {
    var jwks = await getJwks(JWKSUrl);

    try {
      let keyStore = await jose.JWK.asKeyStore(jwks);

      let result = await jose.JWS.createVerify(keyStore).verify(compactJWS);
      let payload = JSON.parse(Buffer.from(result.payload).toString());

      return payload;
    } catch (error) {
      throw "Error with verifying JWS";
    }
  }

Error Handling

The RESTful APIs used HTTP specification standard status codes to indicate the success or failure of each request. Except gateway errors, the response content will be in the following JSON format:

{
    "code": "integer (int32)",
    "message": "string"
}

Refer to the individual API definitions for the error codes partner might encounter for each API.

Support

Please refer to the NDI {api} Portal for the following supporting materials where relevant:

For technical queries, contact support@myinfo.gov.sg. For business queries, contact partner@myinfo.gov.sg.

Authentication

ClientAssertion

PKI digital signature of assertion metadata for client authentication. Signature will be verified using the public signing key listed in Relying Party's JWKS.

Security Scheme Type clientassertion

PKCE

OAuth security extention to prevent CSRF and authorization code injection attacks. This replaces the 'state' parameter.

Security Scheme Type PKCE

OAuth2

The following are the available OAuth2 scopes for MyInfo APIs

Security Scheme Type OAuth2
authorizationCode OAuth Flow
Authorization URL: /com/v4/authorize
Token URL: /com/v4/token
Scopes:
  • uinfin -

    NRIC/FIN

  • partialuinfin -

    Partial NRIC/FIN

  • name -

    Principal Name

  • aliasname -

    Alias Name

  • hanyupinyinname -

    Hanyu Pinyin Name

  • hanyupinyinaliasname -

    Hanyu Pinyin Alias Name

  • marriedname -

    Married Name

  • sex -

    Sex

  • race -

    Race

  • secondaryrace -

    Secondary Race

  • dialect -

    Dialect

  • dob -

    Date of Birth

  • residentialstatus -

    Residential Status

  • nationality -

    Nationality/Citizenship

  • birthcountry -

    Country/Place of Birth

  • passportnumber -

    Passport Number

  • passportexpirydate -

    Passport Expiry Date

  • passtype -

    Pass Type

  • passstatus -

    Pass Status

  • passexpirydate -

    Pass Expiry Date

  • employmentsector -

    Employment Sector

  • mobileno -

    Mobile Number

  • email -

    Email Address

  • regadd -

    Registered Address

  • hdbtype -

    Type of HDB

  • housingtype -

    Type of Housing

  • academicqualifications -

    Academic Qualifications

  • cpfbalances -

    CPF Account Balance

  • cpfcontributions -

    CPF Contribution History (up to 15 months)

  • cpfemployers -

    Employers as stated in CPF Contribution History (up to 15 months)

  • cpfhousingwithdrawal -

    CPF Housing Withdrawal

  • cpfinvestmentscheme.sdsnetshareholdingqty -

    CPF Investment Scheme - Number of Discounted Shares

  • cpfinvestmentscheme.account -

    CPF Investment Scheme - Account

  • cpfinvestmentscheme.saqparticipationstatus -

    CPF Investment Scheme - Self-Awareness Questionnaire (SAQ) Participation Status

  • cpfhomeprotectionscheme -

    CPF Home Protection Scheme

  • cpfdependantprotectionscheme -

    CPF Dependant Protection Scheme

  • cpfmedishieldlife -

    CPF MediShield Life

  • cpfrstucurrentyeartaxrelief -

    CPF Retirement Sum Topping-Up Scheme Current Year Tax Relief

  • cpfrstuselftopupamount -

    CPF Retirement Savings Topping-up Scheme - Maximum amount you can top-up using cash and CPF

  • cpflife -

    CPF Lifelong Income For the Elderly (CPF LIFE)

  • cpfmonthlypayouts -

    CPF Monthly Payouts (Non-LIFE)

  • noa-basic -

    Notice of Assessment (Basic, Latest Year)

  • noahistory-basic -

    Notice of Assessment (Basic, Last 2 Years)

  • noa -

    Notice of Assessment (Detailed, Latest Year)

  • noahistory -

    Notice of Assessment (Detailed, Last 2 Years)

  • ownerprivate -

    Ownership of Private Residential Property

  • employment -

    Name of Employer

  • occupation -

    Occupation

  • marital -

    Marital Status

  • marriagedate -

    Marriage Date

  • marriagecertno -

    Marriage Certificate Number

  • countryofmarriage -

    Country of Marriage

  • divorcedate -

    Divorce Date

  • childrenbirthrecords.birthcertno -

    Children Birth Records - Birth Cert Number

  • childrenbirthrecords.name -

    Children Birth Records - Name

  • childrenbirthrecords.aliasname -

    Children Birth Records - Alias Name

  • childrenbirthrecords.hanyupinyinname -

    Children Birth Records - Hanyu Pinyin Name

  • childrenbirthrecords.hanyupinyinaliasname -

    Children Birth Records - Hanyu Pinyin Alias Name

  • childrenbirthrecords.marriedname -

    Children Birth Records - Married Name

  • childrenbirthrecords.sex -

    Children Birth Records - Sex

  • childrenbirthrecords.race -

    Children Birth Records - Race

  • childrenbirthrecords.secondaryrace -

    Children Birth Records - Secondary Race

  • childrenbirthrecords.dob -

    Children Birth Records - Date of Birth

  • childrenbirthrecords.tob -

    Children Birth Records - Time of Birth

  • childrenbirthrecords.dialect -

    Children Birth Records - Dialect

  • childrenbirthrecords.lifestatus -

    Children Birth Records - Life Status

  • childrenbirthrecords.vaccinationrequirements -

    Children Birth Records - Vaccination Requirements

  • childrenbirthrecords.sgcitizenatbirthind -

    Children Birth Records - Singapore Citizen at Birth Indicator

  • sponsoredchildrenrecords.nric -

    Sponsored Children Records - NRIC / FIN

  • sponsoredchildrenrecords.name -

    Sponsored Children Records - Name

  • sponsoredchildrenrecords.aliasname -

    Sponsored Children Records - Alias Name

  • sponsoredchildrenrecords.hanyupinyinname -

    Sponsored Children Records - Hanyu Pinyin Name

  • sponsoredchildrenrecords.hanyupinyinaliasname -

    Sponsored Children Records - Hanyu Pinyin Alias Name

  • sponsoredchildrenrecords.marriedname -

    Sponsored Children Records - Married Name

  • sponsoredchildrenrecords.sex -

    Sponsored Children Records - Sex

  • sponsoredchildrenrecords.race -

    Sponsored Children Records - Race

  • sponsoredchildrenrecords.secondaryrace -

    Sponsored Children Records - Secondary Race

  • sponsoredchildrenrecords.dialect -

    Sponsored Children Records - Dialect

  • sponsoredchildrenrecords.dob -

    Sponsored Children Records - Date of Birth

  • sponsoredchildrenrecords.birthcountry -

    Sponsored Children Records - Country/Place of Birth

  • sponsoredchildrenrecords.lifestatus -

    Sponsored Children Records - Life Status

  • sponsoredchildrenrecords.residentialstatus -

    Sponsored Children Records - Residential Status

  • sponsoredchildrenrecords.nationality -

    Sponsored Children Records - Nationality/Citizenship

  • sponsoredchildrenrecords.scprgrantdate -

    Sponsored Children Records - SC / PR / LTVP Grant Date

  • sponsoredchildrenrecords.vaccinationrequirements -

    Sponsored Children Records - Vaccination Requirements

  • vehicles.vehicleno -

    Vehicles - Vehicle Number

  • vehicles.type -

    Vehicles - Vehicle Type

  • vehicles.iulabelno -

    Vehicles - IU Label Number

  • vehicles.make -

    Vehicles - Vehicle Make

  • vehicles.model -

    Vehicles - Vehicle Model

  • vehicles.chassisno -

    Vehicles - Chassis Number

  • vehicles.engineno -

    Vehicles - Engine Number

  • vehicles.motorno -

    Vehicles - Motor Number

  • vehicles.yearofmanufacture -

    Vehicles - Year of Manufacture

  • vehicles.firstregistrationdate -

    Vehicles - First Registration Date

  • vehicles.originalregistrationdate -

    Vehicles - Original Registration Date

  • vehicles.coecategory -

    Vehicles - COE Category

  • vehicles.coeexpirydate -

    Vehicles - COE Expiry Date

  • vehicles.roadtaxexpirydate -

    Vehicles - Road Tax Expiry Date

  • vehicles.quotapremium -

    Vehicles - Quota Premium

  • vehicles.openmarketvalue -

    Vehicles - Open Market Value

  • vehicles.co2emission -

    Vehicles - CO2 Emission Rate

  • vehicles.status -

    Vehicles - Vehicle Status

  • vehicles.primarycolour -

    Vehicles - Primary Colour

  • vehicles.secondarycolour -

    Vehicles - Secondary Colour

  • vehicles.attachment1 -

    Vehicles - Attachment 1

  • vehicles.attachment2 -

    Vehicles - Attachment 2

  • vehicles.attachment3 -

    Vehicles - Attachment 3

  • vehicles.scheme -

    Vehicles - Vehicle Scheme

  • vehicles.thcemission -

    Vehicles - THC Emission Rate

  • vehicles.coemission -

    Vehicles - CO Emission Rate

  • vehicles.noxemission -

    Vehicles - NOx Emission Rate

  • vehicles.pmemission -

    Vehicles - PM Emission Rate

  • vehicles.enginecapacity -

    Vehicles - Engine Capacity

  • vehicles.powerrate -

    Vehicles - Power Rate

  • vehicles.effectiveownership -

    Vehicles - Effective Date/Time of Ownership

  • vehicles.propellant -

    Vehicles - Propellant

  • vehicles.maximumunladenweight -

    Vehicles - Max Unladen Weight

  • vehicles.maximumladenweight -

    Vehicles - Max Laden Weight

  • vehicles.minimumparfbenefit -

    Vehicles - Minimum PARF Benefit

  • vehicles.nooftransfers -

    Vehicles - No. of Transfers

  • vehicles.vpc -

    Vehicles - Vehicle Parking Certificate

  • drivinglicence.comstatus -

    Driving Licence - Certificate of Merit Status

  • drivinglicence.totaldemeritpoints -

    Driving Licence - Total Demerit Points

  • drivinglicence.suspension.startdate -

    Driving Licence - Suspension Start Date

  • drivinglicence.suspension.enddate -

    Driving Licence - Suspension End Date

  • drivinglicence.disqualification.startdate -

    Driving Licence - Disqualification Start Date

  • drivinglicence.disqualification.enddate -

    Driving Licence - Disqualification End Date

  • drivinglicence.revocation.startdate -

    Driving Licence - Revocation Start Date

  • drivinglicence.revocation.enddate -

    Driving Licence - Revocation End Date

  • drivinglicence.pdl.validity -

    Driving Licence - Provisional Driving Licence Validity

  • drivinglicence.pdl.expirydate -

    Driving Licence - Provisional Driving Licence Expiry Date

  • drivinglicence.pdl.classes -

    Driving Licence - Provisional Driving Licence Class

  • drivinglicence.qdl.validity -

    Driving Licence - Qualified Driving Licence Validity

  • drivinglicence.qdl.expirydate -

    Driving Licence - Qualified Driving Licence Expiry Date

  • drivinglicence.qdl.classes -

    Driving Licence - Qualified Driving Licence Class

  • drivinglicence.photocardserialno -

    Driving Licence - Photo Card Serial Number

  • hdbownership.noofowners -

    HDB Ownership - Number of Owners

  • hdbownership.address -

    HDB Ownership - Address

  • hdbownership.hdbtype -

    HDB Ownership - Type of HDB Dwelling

  • hdbownership.leasecommencementdate -

    HDB Ownership - Lease Commencement Date

  • hdbownership.termoflease -

    HDB Ownership - Term of Lease

  • hdbownership.dateofpurchase -

    HDB Ownership - Date of Purchase

  • hdbownership.dateofownershiptransfer -

    HDB Ownership - Date of Transfer of Ownership

  • hdbownership.loangranted -

    HDB Ownership - Loan Granted

  • hdbownership.originalloanrepayment -

    HDB Ownership - Original Loan Repayment Period

  • hdbownership.balanceloanrepayment -

    HDB Ownership - Balance Loan Repayment Period

  • hdbownership.outstandingloanbalance -

    HDB Ownership - Outstanding HDB Loan Balance

  • hdbownership.monthlyloaninstalment -

    HDB Ownership - Monthly Loan Instalment

  • hdbownership.outstandinginstalment -

    HDB Ownership - Outstanding Instalment

  • hdbownership.purchaseprice -

    HDB Ownership - Purchase Price

  • ltavocationallicences.tdvl.licencename -

    Licence Name of Taxi Driver's LTA Vocational Licence

  • ltavocationallicences.tdvl.vocationallicencenumber -

    Unique Vocational Licence Number for Taxi Driver's LTA Vocational Licence holder

  • ltavocationallicences.tdvl.expirydate -

    Expiry date of Taxi Driver's LTA Vocational Licence

  • ltavocationallicences.tdvl.status -

    Status of Taxi Driver's LTA Vocational Licence

  • ltavocationallicences.pdvl.licencename -

    Licence Name of Private Hire Car driver's LTA Vocational Licence

  • ltavocationallicences.pdvl.vocationallicencenumber -

    Unique Vocational Licence Number for Private Hire Car driver's LTA Vocational Licence holder

  • ltavocationallicences.pdvl.expirydate -

    Expiry date of Private Hire Car driver's LTA Vocational Licence

  • ltavocationallicences.pdvl.status -

    Status of Private Hire Car driver's LTA Vocational Licence

  • ltavocationallicences.bdvl.licencename -

    Licence Name of Bus driver's LTA Vocational Licence

  • ltavocationallicences.bdvl.vocationallicencenumber -

    Unique Vocational Licence Number for Bus driver's LTA Vocational Licence holder

  • ltavocationallicences.bdvl.expirydate -

    Expiry date of Bus driver's LTA Vocational Licence

  • ltavocationallicences.bdvl.status -

    Status of Bus driver's LTA Vocational Licence

  • ltavocationallicences.bavl.licencename -

    Licence Name of Bus Attendant's LTA Vocational Licence

  • ltavocationallicences.bavl.vocationallicencenumber -

    Unique Vocational Licence Number for Bus Attendant's LTA Vocational Licence holder

  • ltavocationallicences.bavl.expirydate -

    Expiry date of Bus Attendant's LTA Vocational Licence

  • ltavocationallicences.bavl.status -

    Status of Bus Attendant's LTA Vocational Licence

  • ltavocationallicences.odvl.licencename -

    Licence Name of Omnibus driver's LTA Vocational Licence

  • ltavocationallicences.odvl.vocationallicencenumber -

    Unique Vocational Licence Number for Omnibus driver's LTA Vocational Licence holder

  • ltavocationallicences.odvl.expirydate -

    Expiry date of Omnibus driver's LTA Vocational Licence

  • ltavocationallicences.odvl.status -

    Status of Omnibus driver's LTA Vocational Licence

DPoP

Demonstration Proof of Possession, extension that cryptographically bind access tokens to a particular client when they are issued

Security Scheme Type DPoP

MyInfo

RESTful API Definitions

Person-Sample

Retrieves a sample Person data from MyInfo based on UIN/FIN.

This API does not use OAuth2.0 to perform authentication or authorisation, and does not require authorisation token and digital signature.

Note: Null value indicates that an attribute is unavailable.

path Parameters
uinfin
required
string
Example: S9812381D
query Parameters
scope
Array of strings
Example: scope=name hanyupinyinname

Space separated list of scope requested. Possible scopes are listed in the scopes of the OAuth2 Security Schema above.

Responses

Request samples

curl https://sandbox.api.myinfo.gov.sg/com/v4/person-sample/S9812381D

Response samples

Content type
application/json
{
  • "partialuinfin": {
    },
  • "uinfin": {
    },
  • "name": {
    },
  • "hanyupinyinname": {
    },
  • "aliasname": {
    },
  • "hanyupinyinaliasname": {
    },
  • "marriedname": {
    },
  • "sex": {
    },
  • "race": {
    },
  • "secondaryrace": {
    },
  • "dialect": {
    },
  • "nationality": {
    },
  • "dob": {
    },
  • "birthcountry": {
    },
  • "residentialstatus": {
    },
  • "passportnumber": {
    },
  • "passportexpirydate": {
    },
  • "regadd": {
    },
  • "housingtype": {
    },
  • "hdbtype": {
    },
  • "hdbownership": [
    ],
  • "ownerprivate": {
    },
  • "email": {
    },
  • "mobileno": {
    },
  • "marital": {
    },
  • "marriagecertno": {
    },
  • "countryofmarriage": {
    },
  • "marriagedate": {
    },
  • "divorcedate": {
    },
  • "childrenbirthrecords": [
    ],
  • "sponsoredchildrenrecords": [
    ],
  • "occupation": {
    },
  • "employment": {
    },
  • "passtype": {
    },
  • "passstatus": {
    },
  • "passexpirydate": {
    },
  • "employmentsector": {
    },
  • "vehicles": [
    ],
  • "drivinglicence": {
    },
  • "academicqualifications": {
    },
  • "ltavocationallicences": {
    },
  • "chas": {
    },
  • "merdekagen": {
    },
  • "pioneergen": {
    },
  • "noa-basic": {
    },
  • "noa": {
    },
  • "noahistory-basic": {
    },
  • "noahistory": {
    },
  • "cpfcontributions": {
    },
  • "cpfemployers": {
    },
  • "cpfbalances": {
    },
  • "cpfhousingwithdrawal": {
    },
  • "cpfhomeprotectionscheme": {
    },
  • "cpfdependantprotectionscheme": {
    },
  • "cpfinvestmentscheme": {
    },
  • "cpfmedishieldlife": {
    },
  • "cpfrstucurrentyeartaxrelief": {
    },
  • "cpfrstuselftopupamount": {
    },
  • "cpflife": {
    },
  • "cpfmonthlypayouts": {
    }
}

Authorise

This API triggers SingPass login and obtain consent for the user to retrieve user's data from MyInfo. Once the user has authenticated and consented, an authorisation code (authcode) will be returned via the callback URL defined. The authcode can then be used to retrieve an access token via the Token API.

Note: This API is public and should be implemented as a link or button on partner's online webpage. Note: For partners integrating via android mobile application, please ensure that the "setDomStorageEnable" attribute is enabled.

query Parameters
purpose_id
required
string

purpose_id should have a corresponding pre-registered purpose(s) description as part of the setup. Purpose description refers to what the user will see in the consent page

response_type
required
string
Default: "code"

Response type for authorisation code flow - must be "code".

scope
required
Array of strings
Example: scope=name hanyupinyinname

Space separated list of scopes requested. Possible scopes are listed in the scopes of the OAuth2 Security Schema above.

code_challenge
required
string
Example: code_challenge=BuXV0_h20H2KgRkhQ2cwDKDkSOcctPPozQv0JRP8D8k

Value resulting from performing Base64 encoding of a SHA256 hash of code_verifier (cryptographic random value generate on server side.) Refer to the section on Proof Key for Code Exchange (PKCE) for more information.

code_challenge_method
required
string
Example: code_challenge_method=S256

Hashing method used in producing code_challenge. Only supports 'S256'

redirect_uri
required
string

Partner's callback URL for MyInfo to return with the authorisation code.

client_id
required
string
Example: client_id=STG-180099999K-TEST01

Unique ID for partner's application.

app_launch_url
string

Url scheme to launch back user's mobile app after successful authentication using SingPass mobile.

subentity_id
string
Example: subentity_id=180099736H

UEN of the SaaS partner's client that will be receiving the person data.

Responses

Request samples

function callAuthorizeApi() {
  var authorizeUrl = authApiUrl + "?client_id=" + clientId
    + "&scope="+ scope
    + "&redirect_uri=" + redirectUrl
    + "&response_type=code"
    + "&code_challenge=" + codeChallenge
    + "&code_challenge_method=S256"
    + "&purpose_id=" + purposeId

  window.location = authorizeUrl;
}

Token

This API generates an access token when presented with a valid authcode obtained from the Authorise API. This token can then be used to request for the user's data that were consented.

Authorizations:
header Parameters
DPoP
required
string

DPoP Proof (JWT) containing the partner's ephemeral public signing key that can be used to prove legit possession of the access token issued.

Request Body schema: application/x-www-form-urlencoded
code
required
string

The authcode given by the authorise API.

grant_type
required
string
Default: "authorization_code"

Grant type for getting token (default "authorization_code")

client_id
required
string

Unique ID for your application.

redirect_uri
required
string

Application's callback URL.

client_assertion
required
string

The assertion being used to authenticate the client. Refer to the Security section on Client Assertion for more details.

client_assertion_type
required
string
Default: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"

The format of the assertion, which is defined to be 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'

code_verifier
required
string

Cryptograhic random string generated and kept secret on serverside. Used to compare with code_challenge sent in the authorize call

Responses

Request samples

//get access token using authcode
async function getAccessToken(authCode, privateSigningKey, codeVerifier, sessionPopKeyPair) {
try {

  let tokenUrl = process.env.MYINFO_API_TOKEN_URL;
  let redirectUrl = process.env.PARTNER_REDIRECT_URL;
  let clientId = process.env.MYINFO_APP_CLIENT_ID;

  let cacheCtl = "no-cache";
  let contentType = "application/x-www-form-urlencoded";
  let method = constant.HTTP_METHOD.POST;
  let clientAssertionType = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
  let jktThumbprint = await generateJwkThumbprint(sessionPopKeyPair.publicKey)
  let clientAssertion = await generateClientAssertion(tokenUrl, clientId, privateSigningKey, jktThumbprint);
  // assemble params for Token API
  let strParams = `grant_type=authorization_code` +
      "&code=" + authCode +
      "&redirect_uri=" + redirectUrl +
      "&client_id=" + clientId +
      "&code_verifier=" + codeVerifier +
      "&client_assertion_type=" + clientAssertionType +
      "&client_assertion=" + clientAssertion

  let params = querystring.parse(strParams);
  let dPoP = await generateDpop(tokenUrl, null,constant.HTTP_METHOD.POST, sessionPopKeyPair);

  // assemble headers for Token API
  let strHeaders = `Content-Type=${contentType}&Cache-Control=${cacheCtl}&DPoP=${dPoP}`;
  let headers = querystring.parse(strHeaders);

  // invoke Token API
  let parsedTokenUrl = urlParser.parse(url);
  let tokenDomain = parsedTokenUrl.hostname;
  let tokenRequestPath = parsedTokenUrl.path;

  return getHttpsResponse(hostname, path, headers, method, params);
} catch (error) {
    throw error;
};

Response samples

Content type
application/json
{
  • "access_token": {
    },
  • "token_type": "Bearer",
  • "expires_in": 0,
  • "scope": "string"
}

Person

This API returns user's data from MyInfo when presented with a valid access token obtained from the Token API.

Note: Null value indicates that an attribute is unavailable.

Authorizations:
path Parameters
sub
required
string
Example: 9E9B2260-47B8-455B-89B5-C48F4DB98322

Identifier of user obtained from 'sub' attribute in access token. May be UINFIN or UUID.

query Parameters
scope
required
Array of strings
Example: scope=name hanyupinyinname

Space separated list of scopes requested. Possible scopes are listed in the scopes of the OAuth2 Security Schema above.

subentity_id
string
Example: subentity_id=180099736H

UEN of SaaS partner's client that will be receiving the person data.

header Parameters
Authorization
required
any

Include the access token (JWT) from /token API in this header prefixed with 'DPoP'.

DPoP
required
any

Include the generated Demonstration of Proof of Possession token.

Responses

Request samples

// function to prepare request for PERSON API
callPersonAPI = async function (uuid, accessToken, sessionEphemeralKeyPair) {
  let urlLink;

  urlLink = CONFIG.PERSON_URL + '/' + uuid;

  let cacheCtl = 'no-cache';
  let method = constant.HTTP_METHOD.GET;

  // assemble params for Person API
  let strParams = 'scope=' + encodeURIComponent(CONFIG.SCOPE);

  // assemble headers for Person API
  let strHeaders = 'Cache-Control=' + cacheCtl;
  let headers = querystring.parse(strHeaders);

  //generate ath to append into DPoP 
  let ath = this.securityHelper.base64URLEncode(this.securityHelper.sha256(accessToken));
  //generate DPoP 
  let dpopToken = await this.securityHelper.generateDpop(urlLink, ath, method, sessionEphemeralKeyPair);
  headers['dpop'] = dpopToken;

  headers['Authorization'] = 'DPoP ' + accessToken;

  // invoke entity person API
  let personURL = CONFIG.PERSON_URL;
  let parsedUrl = urlParser.parse(personURL);
  let domain = parsedUrl.hostname;
  let requestPath = parsedUrl.path + '/' + uuid + '?' + strParams;
  //invoking https to do GET call

  let personData = await requestHandler.getHttpsResponse(method, 'https://' + domain + requestPath, headers, null, null);

  return personData.data;
};

Response samples

Content type
application/json
{
  • "partialuinfin": {
    },
  • "uinfin": {
    },
  • "name": {
    },
  • "hanyupinyinname": {
    },
  • "aliasname": {
    },
  • "hanyupinyinaliasname": {
    },
  • "marriedname": {
    },
  • "sex": {
    },
  • "race": {
    },
  • "secondaryrace": {
    },
  • "dialect": {
    },
  • "nationality": {
    },
  • "dob": {
    },
  • "birthcountry": {
    },
  • "residentialstatus": {
    },
  • "passportnumber": {
    },
  • "passportexpirydate": {
    },
  • "regadd": {
    },
  • "housingtype": {
    },
  • "hdbtype": {
    },
  • "hdbownership": [
    ],
  • "ownerprivate": {
    },
  • "email": {
    },
  • "mobileno": {
    },
  • "marital": {
    },
  • "marriagecertno": {
    },
  • "countryofmarriage": {
    },
  • "marriagedate": {
    },
  • "divorcedate": {
    },
  • "childrenbirthrecords": [
    ],
  • "sponsoredchildrenrecords": [
    ],
  • "occupation": {
    },
  • "employment": {
    },
  • "passtype": {
    },
  • "passstatus": {
    },
  • "passexpirydate": {
    },
  • "employmentsector": {
    },
  • "vehicles": [
    ],
  • "drivinglicence": {
    },
  • "academicqualifications": {
    },
  • "ltavocationallicences": {
    },
  • "chas": {
    },
  • "merdekagen": {
    },
  • "pioneergen": {
    },
  • "noa-basic": {
    },
  • "noa": {
    },
  • "noahistory-basic": {
    },
  • "noahistory": {
    },
  • "cpfcontributions": {
    },
  • "cpfemployers": {
    },
  • "cpfbalances": {
    },
  • "cpfhousingwithdrawal": {
    },
  • "cpfhomeprotectionscheme": {
    },
  • "cpfdependantprotectionscheme": {
    },
  • "cpfinvestmentscheme": {
    },
  • "cpfmedishieldlife": {
    },
  • "cpfrstucurrentyeartaxrelief": {
    },
  • "cpfrstuselftopupamount": {
    },
  • "cpflife": {
    },
  • "cpfmonthlypayouts": {
    }
}