SG-Verify Webhook Specifications (1.0.1)

Download OpenAPI specification:Download

API Specifications for implementing Webhook for SG-Verify service.

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

Release Notes

  • 1.0.1 (02 Sept 2019)
    • Deprecated homeno & mailadd attribute
  • 1.0.0 (01 July 2019)
    • initial draft

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

SG-Verify is a service provided by SingPass Mobile that allows easy sharing of customer basic personal information to an organization. Some example uses of SG-Verify can be:

  • Building Visitor Management System

How Does SG-Verify Work?

The following diagram illustrates how the SG-Verify work: Overview

  1. Customer scans QR code at counter with SingPass Mobile app and consents to share personal info with partner counter
  2. SingPass Mobile invokes backend API
  3. API Gateway pushes encrypted and signed personal info to partner webhook
  4. Partner webhook updates counter display with name of the customer

NOTE: As a partner, in order to use SG-Verify, you will need to implement your webhook according to this specification.

Security

HTTPS Interface

Ensure that your webhook implements the following HTTPS channel encryption:

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

    • 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 you may use:

    • TLS_RSA_WITH_AES_256_GCM_SHA384
    • TLS_RSA_WITH_AES_128_GCM_SHA256
    • TLS_RSA_WITH_AES_256_CBC_SHA256
    • TLS_RSA_WITH_AES_256_CBC_SHA
    • TLS_RSA_WITH_AES_128_CBC_SHA256
    • TLS_RSA_WITH_AES_128_CBC_SHA

IMPORTANT: ensure your server supports TLS 1.1 or 1.2 and supports a cipher suite in the list above.

Application Authentication

Access to your wehbook should be protected with the following minimum criteria:

Prior to implementing your webhook, respective consumers are required to have:

  • approval of access, onboarding process for the required API resources will be provisioned, and
  • authentication credentials are then supplied and exchanged.

NOTE: it is important that your webhook implements the correct authentication mechanism (by checking for the correct API Key provided to you during the onboarding process) to prevent unauthorised access to your webhook.

Payload Signing and Encryption (Person Info)

The payload for the personal information pushed to your webhook is first signed, then encrypted:

Encryption protects the data at rest while a signed payload means, if necessary, you will be able to pass this signed payload to a 3rd party where they can verify the payload's integrity with our public certificate.

In order to read the payload, you have to perform the following steps in order:

  1. Decrypt the payload with your application's private key.
  2. Validate the decrypted payload signature with our public key.

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

STEP 1: Decryption

  • Encryption is done using your application's public key that you provided during onboarding. Decryption of the payload should be using the private key of that key-pair.
  • Current encryption algorithms used:
    • RSA-OAEP (for content key wrapping)
    • AES256GCM (for content encrytion)

Sample Code in NodeJS

  // Sample Code for decrypting JWE
  // Decrypt JWE using private key
  function decryptJWE(header, encryptedKey, iv, cipherText, tag, privateKey) {

    return new Promise((resolve, reject) => {

      var keystore = jose.JWK.createKeyStore();

      var data = {
        "type": "compact",
        "ciphertext": cipherText,
        "protected": header,
        "encrypted_key": encryptedKey,
        "tag": tag,
        "iv": iv,
        "header": JSON.parse(jose.util.base64url.decode(header).toString())
      };
      keystore.add(fs.readFileSync(privateKey, 'utf8'), "pem")
        .then(function(jweKey) {
          // {result} is a jose.JWK.Key
          jose.JWE.createDecrypt(jweKey)
            .decrypt(data)
            .then(function(result) {
              resolve(JSON.parse(result.payload.toString()));
            })
            .catch(function(error) {
              reject(error);
            });
        });

    })
    .catch (error => {
      throw "Error with decrypting JWE";
    })
  }

STEP 2: Verification of Signature

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

  • signature algorithm used is RS256.

Sample Code in NodeJS

  // Sample Code for Verifying & Decoding JWS or JWT
  function verifyJWS(jws, publicCert) {
    // verify payload
    // ignore notbefore check because it gives errors sometimes if the call is too fast.
    try {
      var jwspayload = jwt.verify(jws, fs.readFileSync(publicCert, 'utf8'), {
        algorithms: ['RS256'],
        ignoreNotBefore: true
      });
      return jwspayload;
    }
    catch(error) {
      throw("Error with verifying and decoding JWS");
    }
  }

Understanding the Data Structure

MyInfo Person data follows a specific structure that you need to understand to traverse the data effectively. This section will explain the structure in detail.

The diagram below illustrates how the data is represented logically:
MyInfo Person Data Structure

Data Items (Top-Level)

Each top-level data item can either be a data item object or an array of data item objects. Each data item object will consist of the following properties:

  • classification (Data classification of data field. Default 'C' - Confidential)
  • source (see below)
  • lastupdated (Last updated date of data field. See "full-date" here)
  • unavailable (in certain situations - see below)
  • additional data properties containing data values or arrays

Data Source

The source property indicates the source of data. Possible values are:

  • '1' - Government-verified
  • '2' - User provided
  • '3' - Field is Not Applicable to Person
  • '4' - Verified by SingPass

Note: All Government-verified fields must be non-editable on your digital service form (some exceptions apply - see individual field descriptions).

Data Properties

In each data item, there can be multiple data properties or arrays of data properties.

Each data property will contain either:

  • a value property, or
  • a pair of code and desc properties, or
  • an array of data properties, or
  • other data properties

Note:

  • value property can be strings, numbers, or dates.
  • code and desc pairs will contain the code and its matching description.
  • value is mutually exclusive from (code + desc); i.e. if there is a value, there will not be any code or desc.
  • Where there is code, there will always be a desc - no value will be present.

Exceptions: For these cases, the values will be directly in the property and not in a value, code or desc subproperty:

  • for data item metadata properties; e.g. classification, source, lastupdated, and unavailable
  • for discriminator properties; e.g. type in address formats

Data Not Applicable

Sometimes, a requested data item is not applicable to the person. Examples include:

  • a foreigner will never have a regadd data item.
  • a singapore citizen or permanent resident will never have passtype data item.

For a full list, refer to the "Data Catalog" section of MyInfo API Data in our portal.

Note: When a requested data item is not applicable to the person, the source property will be 3. In such cases, please ignore the data item completely.

Data Item Not Applicable

When a requested data item is not applicable to the entity:

  • for data item objects, the source property will be 3
  • for data item arrays, an empty array will be returned

In such cases, please ignore the data item completely.

Data Property Not Applicable

  • When a data property is not applicable to the person, it will not appear in the schema of that particular entity type.
  • Please check the Person schema to identify which data properties are not applicable to the person type.

Data Unavailable

In other situations, a requested data item might not have any data for that data item from the data source; i.e. data is unavailable. Examples include:

  • when a person does not have any vehicles registered under them

Note: When a requested data item is unavailable:

  • for data item objects, the data item will have the property unavailable with value true.
    In such cases, no additional properties (other than classification, source, and lastupdated) will be provided for the data item.
  • for arrays of data items, an empty array will be returned.

Please display as "Not Available" in your form.

Data Item Unavailable

  • for data item objects, the data item will have the property unavailable with value true.
    In such cases, no additional properties (other than classification, source, lastupdated) will be provided for the data item.
  • for data item arrays, an empty array will be returned.

Please display as "Not Available" in your form.

Data Property Unavailable

  • for data property objects, the value or code/desc will be empty value ("") or NaN.
  • for arrays of data properties, an empty array will be returned.

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

APIKeyAuth

API Key Authentication for SG-Verify to call the webhook.

Security scheme type: API Key
header parameter name: X-API-KEY

SG-Verify

Webhook RESTful API Definitions

Webhook

This webhook allows SG-Verify to push personal data to the partner.

  • The response to application webhook will be a JSON object
  • The value of the identity in the JSON object will be encrypted (JWE wrapping JWS) format
Authorizations:
header Parameters
Authorization
required
any

Authorization credentials. Use API Key for authentication.

Request Body schema: application/json
state
object (State)

Returns the same value as the 'state' parameter sent during QR login process, which allows application to restore application states in a stateless transaction.

timestamp
object (Timestamp)

'Last updated date of data field. See "date-time" in http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'

txnNo
object (Transaction No)

Transaction No for traceability

identity
object

Person's details. Properties shown below are after decryption and decoded from verified JWS.

Responses

200

OK. successful push of personal data.

401

Unauthorized. Invalid credentials.

403

Forbidden

  • Incorrect API URL used.
404

Not Found.

500

Unexpected error. Check response body for actual error.

post /webhook/
Test
https://test.{yourwebhookurl}/webhook/
Production
https://{yourwebhookurl}/webhook/

Request samples

application/json
Copy
Expand all Collapse all
{
  • "state":
    {
    },
  • "timestamp":
    {
    },
  • "txnNo":
    {
    },
  • "identity":
    {
    }
}

Response samples

application/json
Copy
Expand all Collapse all
{
  • "code": 0,
  • "message": "string"
}