# Custom Integration

If your app is written in a language other than Javascript, you'll need to write your own OAuth integration code to integrate with sgID.&#x20;

## Creating an authorization URL

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. You will need to supply the following query string parameters:

| Key            | Value                                                                                                                                                                                                                                           |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| response\_type | Must be set to `code` because sgID only supports the authorization code flow                                                                                                                                                                    |
| client\_id     | Provided to you during [client registration](https://docs.id.gov.sg/1/registration#relying-party-credentials)                                                                                                                                   |
| redirect\_uri  | The callback URL that you provided during [client registration](https://docs.id.gov.sg/1/registration#required-information)                                                                                                                     |
| scope          | A URL-encoded string of the scopes your client will request for                                                                                                                                                                                 |
| nonce          | Randomly generated string to be returned in the id\_token. Used to prevent replay attacks. Refer to the [OpenID Connect documentation](https://openid.net/specs/openid-connect-core-1_0.html#NonceNotes) for implementation details. (OPTIONAL) |
| state          | A unique and non-guessable value associated with each authentication request about to be initiated. Used to prevent CSRF attacks and to maintain state. (RECOMMENDED)                                                                           |

Example URL:

```javascript
https://api.id.gov.sg/v1/oauth/authorize?
    response_type=code
    &client_id=abc
    &scope=openid%20myinfo.name%20myinfo.passport_expiry_date%20myinfo.nric_number
    &redirect_uri=https://example.com/callback
    &nonce=BQO8SV3ALIYA808IZ8O7PKWRI8A8X6MI
    &state=tk39drykro3
```

## Exchange auth code for access token

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

`http://localhost:3000/other_callback?`<mark style="color:orange;">`code`</mark>`=someauthcode&`<mark style="color:orange;">`state`</mark>`=somestate`

Using this authorization code, we can use the SDK to exchange it for an access token, which will be used to retrieve user information. To do so, make a `POST` request to&#x20;

```javascript
https://api.id.gov.sg/v1/oauth/token
```

with the following request body parameters:

| Key            | Value                                                                                                                       |
| -------------- | --------------------------------------------------------------------------------------------------------------------------- |
| client\_id     | Provided to you during [client registration](https://docs.id.gov.sg/1/registration#relying-party-credentials)               |
| client\_secret | Provided to you during [client registration](https://docs.id.gov.sg/1/registration#relying-party-credentials)               |
| 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](https://docs.id.gov.sg/1/registration#required-information) |

You should receive a response with the following attributes:

| Key           | Value                                                                                                                                                                                                                                                                                                                                                                   |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| access\_token | Access Token to be used with retrieving the encrypted payload from user info endpoint                                                                                                                                                                                                                                                                                   |
| id\_token     | <p>JWT token with the associated user claims. Encodes the following: </p><ul><li>iss (hostname)</li><li>sub (end user's unique identifier) </li><li>aud (client id) </li><li>nonce (only returned if provided in authorization url) </li><li>exp (seconds before auth request and access token expires) </li><li>iat (timestamp at which id token was issued)</li></ul> |

Example JSON response body:

```javascript
{
    "access_token": "I6zGnxYTy4fZubtb7LcG48K1fHWb5b",
    "id_token": "eyJhbGciOiJ...[truncated]...L6zm6LaWfkBoA",
}
```

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 are available at <https://api.id.gov.sg/.well-known/jwks.json>&#x20;

## Request for user info

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&#x20;

```javascript
https://api.id.gov.sg/v1/oauth/userinfo
```

with the access token you received in the previous step. Example request:

```
GET /v1/oauth/userinfo HTTP/1.1
Host: api.id.gov.sg
Authorization: Bearer I6zGnxYTy4fZubtb7LcG48K1fHWb5b
Content-Length: 57
Content-Type: application/json
```

You should receive a response with the following attributes:

| Key  | Value                                                                                                                                                                                                                                                                                                                                                                                                             |
| ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| sub  | <p>End user's unique identifier for your client - This is the same value as the <code>sub</code> claim in the <code>id\_token</code> returned from the previous response. </p><p></p><p>Note that as part of sgID's privacy-preserving measures, each end user's unique identifier is different for each sgID client</p>                                                                                          |
| key  | An AES-128-GCM symmetric key, or a **block key**, that is encrypted with your client's RSA-2048 public key.                                                                                                                                                                                                                                                                                                       |
| data | <p>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 <strong>block key</strong> referenced in the definition for the <code>key</code> attribute in the same response body. </p><p></p><p>Refer to the <a href="#decrypting-the-payload">following section</a> for instructions on decrypting the payload.</p> |

Example JSON response body:

```javascript
{
    "sub": "abcdef",
    "key": "eyJhbGcDpgYRL4chyXTjgim...[truncated]...Gxa2tO7nghnu-ewD5ZqA",
    "data": {
        // Note: this will contain all the scopes you requested
        "myinfo.nric_number": "eyJlbmMiOiJ...[truncated]...QafqHmGERc3A",
        "myinfo.name": "eyJlbmMiOi...[truncated]...UgJ9hDSTNLVw",
        "myinfo.passport_expiry_date": "eyJlbmMiOi...[truncated]...UvS41pKk9VKQ",
    }
}
```

## Decrypting the payload

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 is itself encrypted with your client's public key so that only your client has access to the block key.&#x20;

Therefore, to obtain the user data in plaintext, you will need to:

1. Decrypt the `key` received from the user info response with **your client private key**. This will give you the **block key**
2. Decrypt the `data` received from the user info response with the **block key** you have just obtained

![An illustration of how to decrypt the data you received from the user info endpoint](https://308110436-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MYTdG4Jr_PeC9JOgvBN%2Fuploads%2Fpi01KvY8WPLlzlfv7a0R%2FScreenshot%202022-07-14%20at%209.34.00%20PM.png?alt=media\&token=988d4e14-113b-487c-916c-050cb2a71a9a)

Examples decryption:

{% tabs %}
{% tab title="Javascript" %}

```javascript
// We use the node-jose package for working with JWEs and JWKs
// https://github.com/cisco/node-jose
import { JWE, JWK } from 'node-jose'

/**
* Decrypts data into an object of
* plaintext key-value pairs
*
* @param {string} encKey - encrypted block key
* @param {array} block - data
* @param {string} privateKeyPem - private key in pem format
* @returns {object}
*/
async function decryptData(encKey, block, privateKeyPem) {
 const result = {}
 
 // Decrypted encKey to get block key
 const privateKey = await JWK.asKey(privateKeyPem, 'pem')
 const key = await JWE.createDecrypt(privateKey).decrypt(encKey)
 
 // Parse the block key
 const decryptedKey = await JWK.asKey(key.plaintext, 'json')
 
 // Decrypt data
 for (const [key, value] of Object.entries(block)) {
   const { plaintext } = await JWE.createDecrypt(decryptedKey).decrypt(value)
   result[key] = plaintext.toString('ascii')
 }

 return result
}
```

{% endtab %}

{% tab title="WIP" %}

{% endtab %}
{% endtabs %}

Example of decrypted data:

```javascript
{
  "myinfo.name": "TIMOTHY TAN CHENG GUAN",
  "myinfo.nric_number": "S3000786G",
  "myinfo.passport_expiry_date": "2024-01-01",
}
```
