# 5. The Userinfo Request

{% hint style="info" %}
This step is applicable only to Myinfo (v5) apps.
{% endhint %}

The final step in the Singpass authentication flow is the userinfo request. This involves making a GET request to our `userinfo_endpoint` (as defined in our [OpenID configuration](https://docs.developer.singpass.gov.sg/docs/technical-specifications/technical-concepts/openid-connect-discovery)) to retrieve user information. To do this, you will need an access token (obtained from a successful token request)

The endpoint will only return information based on the scopes that you have requested when making the authorization request.

## Request

Just like the authorization request and token request, you will need to include the [DPoP header](https://docs.developer.singpass.gov.sg/docs/technical-specifications/technical-concepts/demonstrating-proof-of-possession-dpop) when making the `/userinfo` request. You will also need to include your access token in the `Authorization` header. The access token should be prefixed with `DPoP` , as shown in the sample request below.

No query parameters are required for this request.

<details>

<summary>Sample request</summary>

{% code overflow="wrap" %}

```http
GET /userinfo HTTP/1.1
Host: id.singpass.gov.sg
Authorization: DPoP eyJ0eXAiOiJhdCtqd3QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiJ1c2VyLWphbmUtZG9lIiwiYXVkIjoiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20vZGF0YSIsImV4cCI6MTc1NjczMDM4MCwiaWF0IjoxNzI1MTk0MzgwLCJqdGkiOiJ0eC0xMjMtYWJjIiwiY25mIjp7ImprdCI6Ik93SWlGaVl2T0NXRkpiV1hlbUdUZzRtU1NYQkNwZk9NaFhRV21XOTBVSEEifX0.dGhpcy1pcy1hLXBsYWNlaG9sZGVyLXNpZ25hdHVyZS1hcy1pdC1yZXF1aXJlcy1hLXByaXZhdGUta2V5
DPoP: eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3Arand0IiwiandrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiQXNWakh4elZ4MURaNnNKcEpzUnM2ek5YYXFmcFR3UmNfcXV0bWw0aEFJQSIsInkiOiI0SkhwVVZDRE5DaXhOTW9OclIzSElodFRzTWNfMF9NcmdpMzJxR3VoUkQ4In19.eyJqdGkiOiIyZmM3Y2Q4ZC0xN2IzLTRlYTUtYTg4ZC1lZWM0NTY5M2JhZDQiLCJodG0iOiJHRVQiLCJodHUiOiJodHRwczovL2lkLnNpbmdwYXNzLmdvdi5zZy91c2VyaW5mbyIsImlhdCI6MTc1NjcwODI0N30.wBYjFQRzY2o5aG82LjR1X8qT9bZ-jK3c7hI5fE0gP9vR_7sU6tW5xV4yZ3aB2cE1dF0eG9hI8jJ7kL6mN5oP4qR
```

{% endcode %}

</details>

## Response

### Successful Response

The response body of a successful response will contain a JSON Web Signature (JWS), which is also encrypted via JSON Web Encryption (JWE), represented in compact seralization form. This is the same encryption and signature scheme that was used in our ID token encryption, so you can decrypt and verify the response in exactly the same manner.

The decrypted (and decoded) response is a JSON object with the following fields:

<table><thead><tr><th width="157.6640625">Field</th><th>Description</th><th>Data Type</th></tr></thead><tbody><tr><td><code>person_info</code></td><td>The personal data of the user. The information returned in this field depends on the scopes that were requested in your authorization request.</td><td>A JSON object that follows the <a href="https://public.cloud.myinfo.gov.sg/myinfo/api/myinfo-kyc-v4.0.html#operation/getperson">Myinfo Get Person response</a>. You can also download the OpenAPI specifications for this property below.</td></tr><tr><td><code>iss</code></td><td>The issuer identifier of our authorization server. This is identical to the <code>iss</code> returned in the ID token.</td><td>String</td></tr><tr><td><code>iat</code></td><td>The unix timestamp at which we issued this JWT.</td><td>String</td></tr><tr><td><code>sub</code></td><td>The principal that is the subject of the JWT. Contains a globally unique identifier for the user. This is identical to the <code>sub</code> returned in the ID token.</td><td>String</td></tr><tr><td><code>aud</code></td><td>The client ID of your registered client, provided by Singpass during app onboarding.</td><td>A 32-character case-sensitive alphanumeric string.</td></tr></tbody></table>

The specifications for the `person_info` property is also available in OpenAPI format:

{% file src="<https://2816701917-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FW3T7d7fy7OGYkZf4zVKU%2Fuploads%2FTu4AGW0HQbNBt3uFAkQl%2Fperson_info_openapi.yml?alt=media&token=d093cc3c-3c2b-4a15-9c3d-f163f4ced2bf>" %}

The examples below show how the response would look like if `openid uinfin name` were the requested scopes.

<details>

<summary>Sample encrypted response (this is a JWE)</summary>

<pre data-overflow="wrap"><code><strong>eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiRUNESC1FUytBMjU2S1ciLCJraWQiOiJ0ZXN0LXJwLWtleS0wMSIsImVwayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6Ik1RVTBWRnlfUWFUYktzTmJrVTdMZkFnUjJ2Y1FQYW94UzBXM2RLRm9yOU0iLCJ5IjoibkdRam5PRlZ4emdzRERjMUJqQ3otZi1KeUY4VC14WW0xQVp4NjFtZWVCOCJ9fQ.gDvjBmkLqQ42hbNM2ULPwaskGPBlLvslPAqr0XcN2a-OYqOHXKfwvoUUOuoibTfzg_l8rr-WalvY8FY_a8yfHOaL2GLt6ZWj.O_tgtrTbPRbL_p0Y2rvnCQ.38npNWj1nL1AQxS2A3JrxokxHms6GPYT2OFhaFghI7N0QkR48gPuUvKi-m7wPbESTYA-9O-bSHEX9fUXD4FtlztrhjRTpGmdfppooVMn9_bHcLLyHbHnS3_yW5JaybqHNfD6zXCB1pw24vvHfGmRJ7C86CeBgosuYslMk7y7m_rIT6YhVnotN_kRBOppVW9eC3g0upRxXQJ3O10__pR-QcBb_eXKqwm6tcpeTEqBPl0Dbedk6DDoq6KSRV5LzyFLMutAjInQpKGdWYa7FCgfHL3FWNfcwyPq27s3d14ArZJVkIJsOW_VTI_lrnSBzCcdJpbGj9wPe0e2SfslliZlSxYTTpECyV5AZZgwxz0pMaE85Ob7KzrJjMdbZqZZC53HnZmq6pS8RiUce4950IwvsfF0xDUDaZuMxKnISoPcuUX2jHr8FG0SytO8Pr6m3DyOYbQnSkUFdjCRSHiKRqDxlqM15hSkle3jtd9qf-EzuGeHNqaJCjD7XWeviwJgD70fUZDM8lDvCp5mTfl0pcy7mlGEWjVmfR3MB1ohGwkZLeq3H_KrCyhn_FJ-DRPiE4oIaO8oSsFOhRocND4RDlliOIRK_B1XRmw1YpJFBRpn04N2ytnJrxCJ4cZeTEa4QCYkKaJHPqWkN_qvdgxywkwELLB5Tb1sgdKcq3Kh77uHWl7AfZF9iE1L-kgg4hT5KaJSp4qEYz-nbb4TqmrsnZiPbjnzSFrOGZ778OpDWnXhbb5VcXk9ZjejEdBtoqnIJ_vubEWTw-ZeMI4fCmNuiZ4HnY130VKfnU2f19GSNYaeL7GX7bVQWVS_H01mbll6_GUe.g7la6rSFevvuUrEoqVb41SQB1dk4JuTkrl8zwE0fzG4
</strong></code></pre>

</details>

<details>

<summary>Sample decrypted response (this is a JWS)</summary>

{% code overflow="wrap" %}

```
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImFsaWFzL3N0Zy1zcC1hdXRoLWFwaS1pZC10b2tlbi1zaWduaW5nLWtleS1rbXMtYXN5bW1ldHJpYy1rZXktYWxpYXMifQ.eyJwZXJzb25faW5mbyI6eyJ1aW5maW4iOnsibGFzdHVwZGF0ZWQiOiIyMDI0LTA5LTI2Iiwic291cmNlIjoiMSIsImNsYXNzaWZpY2F0aW9uIjoiQyIsInZhbHVlIjoiUzkwMDAwMDFCIn0sIm5hbWUiOnsibGFzdHVwZGF0ZWQiOiIyMDI0LTA5LTI2Iiwic291cmNlIjoiMSIsImNsYXNzaWZpY2F0aW9uIjoiQyIsInZhbHVlIjoiU09IIEhBTyBGRU5HIn19LCJpc3MiOiJodHRwczovL2lkLnNpbmdwYXNzLmdvdi5zZy9mYXBpIiwic3ViIjoiZDQ1ZDhmMjEtNjE3OC00NzEzLWI5NjItODYzNWVkMmE5NDVhIiwiYXVkIjoiVDVzTTVhNTNZYXczVVJ5REV2Mnk5MTI5Q2JFbENOMkYiLCJpYXQiOjE3NDY2NzgwODl9.Tmvh5V_BN0fMBgqa2-Z4vG_Ayp_OoeWfyQrWMZjG9y9NBFwyRnjMpwDK_qFzkn_0D7AjOX-np6p3Nk5KFwvKiA
```

{% endcode %}

</details>

<details>

<summary>Sample decoded response payload</summary>

```json
{
  "person_info": {
    "uinfin": {
      "lastupdated": "2024-09-26",
      "source": "1",
      "classification": "C",
      "value": "S9000001B"
    },
    "name": {
      "lastupdated": "2024-09-26",
      "source": "1",
      "classification": "C",
      "value": "SOH HAO FENG"
    }
  },
  // above scopes are returned in the same format as the Myinfo Get Person response
  "iss": "https://id.singpass.gov.sg/fapi",
  "sub": "d45d8f21-6178-4713-b962-8635ed2a945a",
  "aud": "T5sM5a53Yaw3URyDEv2y9129CbElCN2F",
  "iat": 1746678089
}
```

</details>

### Error Response

If there was an error with the request, we will instead return a response body in `application/json` format with the following parameters:

| `error`             | An error code identifying the type of error that has occurred. | This will be an enum value. The possible values are detailed below. |
| ------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------- |
| `error_description` | A human-readable text description of the error.                | String. This is optional.                                           |

These parameters will also be returned in the `WWW-Authenticate` header if the `error` is `invalid_request`, `invalid_token`, or `invalid_dpop_proof`.

<details>

<summary>Sample error response body</summary>

```json
{
  "error": "invalid_dpop_proof",
  "error_description": "Failed to verify DPoP proof JWT"
}
```

</details>

<details>

<summary>Sample WWW-Authenticate header</summary>

```http
HTTP/1.1 401 Unauthorized
WWW-Authenticate: DPoP
  error="invalid_dpop_proof",
  error_description="Failed to verify DPoP proof JWT"
```

</details>

#### Possible error values

The table below lists the possible values of `error` that we may return:

| error                                                                                    | What this error indicates                                                                                                                                                                                                                                                                                                                                                                                            |
| ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `invalid_token`                                                                          | The access token is invalid or has expired. Note that the access token has a lifetime of 30 minutes.                                                                                                                                                                                                                                                                                                                 |
| `invalid_dpop_proof`                                                                     | The `DPoP` header which you have provided is invalid, expired, or malformed. Read our [DPoP guide](https://docs.developer.singpass.gov.sg/docs/technical-specifications/technical-concepts/demonstrating-proof-of-possession-dpop) and ensure that your implementation follows the instructions in the guide.                                                                                                        |
| `invalid_request`                                                                        | <p>This could be due to one of the following:</p><ul><li>Your JWKS endpoint is not reachable, or the JWKS being returned is malformed., Read our guide on <a href="../../technical-concepts/json-web-key-sets-jwks#requirements-for-jwks">JWKS</a> and ensure that you follow the requirements.</li><li>You are trying to retrieve Myinfo data for a Singpass Foreign Account user, which is not possible.</li></ul> |
| <p><code>server\_error</code><br><br><br><br><code>upstream\_depedency\_error</code></p> | <p>The server encountered an unexpected error. You should check <code>error\_description</code> to understand what was the cause of the error.<br><br>When you encounter this error, you may perform up to 3 retries using an exponential backoff strategy. If the request still fails, you should guide users to alternative form-filling methods.</p>                                                              |
