### PKCE Implementation Guide Source: https://docs.developer.singpass.gov.sg/docs/upcoming-changes/fapi-2.0-authentication-api/technical-concepts/proof-key-for-code-exchange-pkce This guide details the steps for implementing PKCE, including generating code verifiers and challenges, and using them in authorization and token exchange requests. ```APIDOC ## PKCE Implementation Guide Proof Key for Code Exchange (PKCE) enhances security by ensuring the requester of an authorization code is the one exchanging it for an access token. It's used in conjunction with client assertions and DPoP to prevent code interception attacks. ### Authorization Request Parameters When making a Pushed Authorization Request, include the following PKCE-related parameters: * **`code_challenge`** (string) - Required - The base64url encoded SHA-256 hash of the `code_verifier`. * **`code_challenge_method`** (string) - Required - Must be set to `S256`. #### Steps to Implement PKCE in Authorization Request: 1. **Generate Code Verifier**: Create a random string between 43-128 characters long. It must contain only alphanumeric characters, dashes (`-`), and underscores (`_`). This string must be unique for each request. * **Example Code Verifier**: `6I9tQd5tKn7Uy9ZfwEqd-YC71gSVfzcfVcyXLc34vQo` 2. **Generate Code Challenge**: Hash the generated `code_verifier` using SHA-256 and then base64url encode the resulting hash. * **Example Code Challenge**: `hu0mAmPq8n91vRqudsGmriiG7blJDJS0bsDeOmEt17M` 3. **Send Parameters**: Include the generated `code_challenge` and set `code_challenge_method` to `S256` in your Pushed Authorization Request. 4. **Store Code Verifier**: Securely store the `code_verifier` on your backend, associated with the user's session, for use in the Token Exchange. ### Token Exchange Parameter During the Token Exchange process, you must include the `code_verifier` that was used to generate the `code_challenge`. #### Request Body Parameter: * **`code_verifier`** (string) - Required - The original, unhashed code verifier generated in step 1 of the Authorization Request. This validates that the token exchange request originates from the same client that initiated the authorization request. ``` -------------------------------- ### Myinfo v4 Person API Request Example (HTTP) Source: https://docs.developer.singpass.gov.sg/docs/upcoming-changes/fapi-2.0-authentication-api/migration-guides/myinfo-v4-apps This HTTP GET request demonstrates the older Person API call from Myinfo v4. It requires the 'sub' from the access token as a path parameter and specific query parameters for scopes, which are no longer needed in the userinfo request. ```http GET /com/v4/person/{sub}?scope=name,uinfin HTTP/1.1 Host: api.myinfo.gov.sg Authorization: DPoP eyJ0eXAiOiJhdCtqd3QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiJ1c2VyLWphbmUtZG9lIiwiYXVkIjoiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20vZGF0YSIsImV4cCI6MTc1NjczMDM4MCwiaWF0IjoxNzI1MTk0MzgwLCJqdGkiOiJ0eC0xMjMtYWJjIiwiY25mIjp7ImprdCI6Ik93SWlGaVl2T0NXRkpiV1hlbUdUZzRtU1NYQkNwZk9NaFhRV21XOTBVSEEifX0.dGhpcy1pcy1hLXBsYWNlaG9sZGVyLXNpZ25hdHVyZS1hcy1pdC1yZXF1aXJlcy1hLXByaXZhdGUta2V5 DPoP: eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3Arand0IiwiandrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiQXNWakh4elZ4MURaNnNKcEpzUnM2ek5YYXFmcFR3UmNfcXV0bWw0aEFJQSIsInkiOiI0SkhwVVZDRE5DaXhOTW9OclIzSElodFRzTWNfMF9NcmdpMzJxR3VoUkQ4In19.eyJqdGkiOiIyZmM3Y2Q4ZC0xN2IzLTRlYTUtYTg4ZC1lZWM0NTY5M2JhZDQiLCJodG0iOiJHRVQiLCJodHUiOiJodHRwczovL2lkLnNpbmdwYXNzLmdvdi5zZy91c2VyaW5mbyIsImlhdCI6MTU3NjcwODI0N30.wBYjFQRzY2o5aG82LjR1X8qT9bZ-jK3c7hI5fE0gP9vR_7sU6tW5xV4yZ3aB2cE1dF0eG9hI8jJ7kL6mN5oP4qR ``` -------------------------------- ### Singpass Authentication Request Example (HTTP) Source: https://docs.developer.singpass.gov.sg/docs/upcoming-changes/fapi-2.0-authentication-api/integration-guide/1 This is a sample HTTP POST request demonstrating how to use Singpass-specific parameters like `transaction_category`, `auth_context_message`, and other standard OAuth 2.0 parameters for authentication. ```http POST /par HTTP/1.1 Content-Type: application/x-www-form-urlencoded DPoP: eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3Arand0IiwiandrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiQXNWakh4elZ4MURaNnNKcEpzUnM2ek5YYXFmcFR3UmNfcXV0bWw0aEFJQSIsInkiOiI0SkhwVVZDRE5DaXhOTW9OclIzSElodFRzTWNfMF9NcmdpMzJxR3VoUkQ4In19.eyJqdGkiOiIyZmM3Y2Q4ZC0xN2IzLTRlYTUtYTg4ZC1lZWM0NTY5M2JjZmUiLCJodG0iOiJQT1NUIiwiaHR1IjoiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20vZGF0YSIsImlhdCI6MTc1NjcwODI0N30.wBYjFQRzY2o5aG82LjR1X8qT9bZ-jK3c7hI5fE0gP9vR_7sU6tW5xV4yZ3aB2cE1dF0eG9hI8jJ7kL6mN5oP4qR Host: id.singpass.gov.sg scope=openid%20sub_account&response_type=code&redirect_uri=https%3A%2F%2Fpartner.gov.sg%2Fredirect&nonce=bb5e1672-a460-4a9b-874e-c38d55ac3922&client_id=T5sM5a53Yaw3URyDEv2y9129CbElCN2F&state=e32b9f28-5d34-4c0f-8b0e-6b670566c97f&code_challenge=MmEbVJBa0kLYEjPAj6p7bSwEc0qy7UPFPQDU-Soltwo&code_challenge_method=S256&transaction_category=authentication&auth_context_message=update%20your%20account%20details ``` -------------------------------- ### GET /userinfo Source: https://docs.developer.singpass.gov.sg/docs/upcoming-changes/fapi-2.0-authentication-api/migration-guides/myinfo-v3-apps Retrieves authenticated user information using DPoP (Demonstration of Proof-of-Possession) authentication. This endpoint replaces the Myinfo v3 Person API and returns user data for all scopes requested during authorization. ```APIDOC ## GET /userinfo ### Description Retrieves authenticated user information using DPoP authentication. This endpoint replaces the Myinfo v3 Person API and returns all user data associated with the scopes requested during the authorization request. ### Method GET ### Endpoint https://id.singpass.gov.sg/userinfo ### Authentication - **Authorization Header**: `DPoP ` - **DPoP Header**: Required - Contains a DPoP proof JWT - **Method**: DPoP (Demonstration of Proof-of-Possession) with access token ### Headers - **Authorization** (string) - Required - Format: `DPoP `. Contains the access token obtained from the token endpoint. - **DPoP** (string) - Required - A signed JWT proof of possession that cryptographically binds the request to the client's key. ### Request Example ``` GET /userinfo HTTP/1.1 Host: id.singpass.gov.sg Authorization: DPoP eyJ0eXAiOiJhdCtqd3QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiJ1c2VyLWphbmUtZG9lIiwiYXVkIjoiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20vZGF0YSIsImV4cCI6MTc1NjczMDM4MCwiaWF0IjoxNzI1MTk0MzgwLCJqdGkiOiJ0eC0xMjMtYWJjIiwiY25mIjp7ImprdCI6Ik93SWlGaVl2T0NXRkpiV1hlbUdUZzRtU1NYQkNwZk9NaFhRV21XOTBVSEEifX0.dGhpcy1pcy1hLXBsYWNlaG9sZGVyLXNpZ25hdHVyZS1hcy1pdC1yZXF1aXJlcy1hLXByaXZhdGUta2V5 DPoP: eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3Arand0IiwiandrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiQXNWakh4elZ4MURaNnNKcEpzUnM2ek5YYXFmcFR3UmNfcXV0bWw0aEFJQSIsInkiOiI0SkhwVVZDRE5DaXhOTW9OclIzSElodFRzTWNfMF9NcmdpMzJxR3VoUkQ4In19.eyJqdGkiOiIyZmM3Y2Q4ZC0xN2IzLTRlYTUtYTg4ZC1lZWM0NTY5M2JhZDQiLCJodG0iOiJHRVQiLCJodHUiOiJodHRwczovL2lkLnNpbmdwYXNzLmdvdi5zZy91c2VyaW5mbyIsImlhdCI6MTc1NjcwODI0N30.wBYjFQRzY2o5aG82LjR1X8qT9bZ-jK3c7hI5fE0gP9vR_7sU6tW5xV4yZ3aB2cE1dF0eG9hI8jJ7kL6mN5oP4qR ``` ### Response #### Success Response (200 OK) Returns user information for all scopes requested during authorization. **Response Fields:** - **person_info** (object) - Contains user attributes with metadata - **[attribute_name]** (object) - Each attribute contains: - **value** (string) - The actual attribute value - **lastupdated** (string) - Last update date (YYYY-MM-DD format) - **source** (string) - Source identifier - **classification** (string) - Data classification level - **iss** (string) - Token issuer identifier - **sub** (string) - Subject UUID - unique identifier for the user - **aud** (string) - Audience - your application's client ID - **iat** (number) - Issued at timestamp (Unix epoch) #### Response Example ```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" } }, "iss": "https://id.singpass.gov.sg/fapi", "sub": "d45d8f21-6178-4713-b962-8635ed2a945a", "aud": "T5sM5a53Yaw3URyDEv2y9129CbElCN2F", "iat": 1746678089 } ``` ### Key Changes from Myinfo v3 1. **No sub in path** - The user's sub is no longer required as a path parameter 2. **DPoP authentication** - PKI signatures are no longer required; use DPoP with access token instead 3. **No query parameters** - Attributes are automatically returned based on authorization scopes 4. **Simplified authorization** - Only requires Authorization and DPoP headers ### Migration Notes - If you need the user's UUID, extract the `sub` claim from the response instead of parsing the access token - All user data is returned automatically based on scopes requested during authorization - No need to specify individual attributes in the request ``` -------------------------------- ### GET /auth Source: https://docs.developer.singpass.gov.sg/docs/upcoming-changes/fapi-2.0-authentication-api/integration-guide/1 Redirects the user to the Singpass authorization URL to initiate the login process. This endpoint requires your client ID and a request URI obtained from a previous pushed authorization request. ```APIDOC ## GET /auth ### Description Redirect the user to the authorization URL to initiate the login process. This is a crucial step after completing the pushed authorization request. ### Method GET ### Endpoint https://id.singpass.gov.sg/auth ### Parameters #### Query Parameters - **client_id** (string) - Required - The client ID of your registered client, provided by Singpass during app onboarding. This must match the client ID used in the pushed authorization request. - **request_uri** (string) - Required - The `request_uri` returned by the pushed authorization request. ### Request Example ```url https://id.singpass.gov.sg/auth?client_id=YOUR_CLIENT_ID&request_uri=YOUR_REQUEST_URI ``` ### Response Upon successful redirection, the user will be prompted to authenticate with Singpass. After authentication, they will be redirected back to the `redirect_uri` specified in your application's configuration. No direct response is received at this endpoint; the interaction is handled via browser redirection. ``` -------------------------------- ### Myinfo v4 Person API Response Example (JSON) Source: https://docs.developer.singpass.gov.sg/docs/upcoming-changes/fapi-2.0-authentication-api/migration-guides/myinfo-v4-apps This JSON structure shows the response format from the Myinfo v4 Person API. User data like 'uinfin' and 'name' were directly available at the root level, unlike the new userinfo response which nests this data under 'person_info'. ```json { "uinfin": { "lastupdated": "2024-09-26", "source": "1", "classification": "C", "value": "S9000001B" }, "name": { "lastupdated": "2024-09-26", "source": "1", "classification": "C", "value": "SOH HAO FENG" } } ``` -------------------------------- ### Singpass Authentication Flow Overview Source: https://docs.developer.singpass.gov.sg/docs/technical-specifications/singpass-authentication-api/overview-of-singpass-flow A detailed sequence diagram illustrating the Singpass login flow, from the user initiating login to the app receiving user tokens, and the optional UserInfo request. ```APIDOC ## Singpass Authentication Flow Overview ### Description This sequence diagram visualizes the entire authentication process when a user logs in using Singpass. It covers the initial request from the user's application frontend and backend to Singpass, the user's interaction with Singpass for authentication and consent, and the subsequent token exchange. It also details the optional UserInfo request to retrieve user details. ### Method N/A (Sequence Diagram) ### Endpoint N/A (Sequence Diagram) ### Parameters N/A (Sequence Diagram) ### Request Example N/A (Sequence Diagram) ### Response N/A (Sequence Diagram) ## Authentication Request Flow ### Description This section describes the initial steps of the Singpass authentication flow, starting from the user clicking the 'Login with Singpass' button. ### Method POST /your-app/backend GET /singpass/authorization ### Endpoint 1. User clicks 'login with Singpass' on your app's frontend. 2. Your app's backend generates `code_verifier`, `code_challenge`, `nonce`, and `state`. 3. Your app's backend constructs an authorization URL with parameters: `scope`, `response_type`, `client_id`, `redirect_uri`, `code_challenge_method`, `code_challenge`, `nonce`, `state`. 4. Your app's backend sets a session cookie and redirects the user to the authorization URL. 5. User is redirected to Singpass for authentication and consent. 6. Singpass generates an authorization code and redirects the user back to your `redirect_uri` with `code` and `state`. ## Token Request Flow ### Description This section details the process of exchanging the authorization code for access and ID tokens. ### Method POST /singpass/token ### Endpoint 1. User is redirected to your app's `redirect_uri` with the authorization code and state. 2. Your app's backend retrieves the `code_verifier`, `state`, and `nonce` associated with the session. 3. Your app's backend verifies the received `state`. 4. Your app's backend generates a client assertion. 5. Your app's backend sends a POST request to Singpass' token endpoint with parameters: `scope`, `grant_type`, `client_id`, `redirect_uri`, `client_assertion_type`, `client_assertion`, `code_verifier`, `code`. 6. Singpass returns an Access Token and an ID Token. 7. Your app's backend decrypts the ID Token (if applicable) and validates it against `iss`, `aud`, and `nonce`. ### Parameters #### Query Parameters (Authorization Request) - **scope** (string) - Required - The scope of the request (e.g., `openid`, `myinfo_access`). - **response_type** (string) - Required - Must be `code` for authorization code flow. - **client_id** (string) - Required - Your application's client ID. - **redirect_uri** (string) - Required - The URI to which Singpass will redirect the user after authentication. - **code_challenge_method** (string) - Required - The method used to generate the code challenge (e.g., `S256`). - **code_challenge** (string) - Required - The challenge generated from the `code_verifier`. - **nonce** (string) - Required - A unique identifier to mitigate replay attacks. - **state** (string) - Required - An opaque value used to maintain state between the request and callback. #### Request Body (Token Request) - **grant_type** (string) - Required - Must be `authorization_code`. - **client_id** (string) - Required - Your application's client ID. - **redirect_uri** (string) - Required - The URI to which Singpass will redirect the user. - **code** (string) - Required - The authorization code received from Singpass. - **code_verifier** (string) - Required - The original code verifier used to generate the code challenge. - **client_assertion_type** (string) - Required - The type of client assertion (e.g., `urn:ietf:params:oauth:client-assertion-type:jwt-bearer`). - **client_assertion** (string) - Required - A JWT assertion signed by your application. ### Request Example (Token Request) ```json { "grant_type": "authorization_code", "client_id": "YOUR_CLIENT_ID", "redirect_uri": "YOUR_REDIRECT_URI", "code": "AUTHORIZATION_CODE_FROM_SINGPASS", "code_verifier": "GENERATED_CODE_VERIFIER", "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", "client_assertion": "YOUR_SIGNED_JWT_ASSERTION" } ``` ### Response #### Success Response (200 - Token) - **access_token** (string) - The access token for making API calls. - **token_type** (string) - The type of token (e.g., `Bearer`). - **expires_in** (integer) - The lifetime in seconds of the access token. - **id_token** (string) - The ID token containing user claims. #### Response Example (Token Response) ```json { "access_token": "ACCESS_TOKEN_FROM_SINGPASS", "token_type": "Bearer", "expires_in": 3600, "id_token": "ID_TOKEN_FROM_SINGPASS" } ``` ## UserInfo Request Flow ### Description This section describes how to retrieve user information after a successful authentication. ### Method GET /singpass/userinfo ### Endpoint 1. Your app's backend sends a GET request to Singpass' userinfo endpoint. 2. The request includes the Access Token in the `Authorization` header as a Bearer Token. 3. Singpass returns a signed and encrypted JWT containing user information. 4. Your app's backend decrypts the userinfo response using your private encryption key. 5. Your app's backend validates the userinfo response against `iss`, `aud`, and `sub`. ### Parameters #### Request Header - **Authorization** (string) - Required - Format: `Bearer YOUR_ACCESS_TOKEN` ### Request Example ```http GET /singpass/userinfo HTTP/1.1 Host: singpass.gov.sg Authorization: Bearer ACCESS_TOKEN_FROM_SINGPASS ``` ### Response #### Success Response (200 - UserInfo) - **Encrypted JWT** (string) - A JWT encrypted using your public key, containing user claims. #### Response Example (UserInfo Response) ```json { "sub": "USER_SUBJECT_ID", "iss": "SINGPASS_ISSUER_URL", "aud": "YOUR_CLIENT_ID", "auth_time": 1678886400, "name": "User Name", "email": "user@example.com" } ``` ``` -------------------------------- ### EC Encryption Key Example with P-256 and ECDH-ES+A128KW Source: https://docs.developer.singpass.gov.sg/docs/technical-specifications/singpass-authentication-api/2.-token-endpoint/client-jwk-requirements Example of a properly formatted EC encryption JWK using P-256 curve with ECDH-ES+A128KW key encryption algorithm. This key includes required attributes: kty (EC), use (enc), kid (timestamped key identifier), crv (curve), x and y coordinates, and alg (encryption algorithm). This example demonstrates the standard format Singpass expects for ID token encryption. ```json { "kty": "EC", "use": "enc", "kid": "enc-2021-01-15T12:09:06Z", "crv": "P-256", "x": "xom6kD54yfXRPvMFVYFlVjUKzmNhz7wf0DP_2h9kXtY", "y": "lrh8C9c8-SBJTm1FcfqLkj2AnHtaxpnB1qsN6PiFFJE", "alg": "ECDH-ES+A128KW" } ``` -------------------------------- ### Creating a New Myinfo (v5) App Source: https://docs.developer.singpass.gov.sg/docs/upcoming-changes/fapi-2.0-authentication-api/migration-guides/myinfo-v4-apps Before integrating with Myinfo (v5), a new app must be created on the Singpass Developer Portal. Existing Myinfo (v4) apps cannot be used. Each Myinfo (v5) app should serve a single purpose. ```APIDOC ## Creating a New Myinfo (v5) App ### Description To integrate with Myinfo (v5), you must create a new application on the Singpass Developer Portal. Existing Myinfo (v4) applications are not compatible with the v5 integration. It is recommended that each Myinfo (v5) application be designed for a single, distinct purpose. If your current v4 application serves multiple purposes, you will need to create separate v5 applications for each. ### Resources - [Create Staging App](https://docs.developer.singpass.gov.sg/docs/singpass-developer-portal-sdp/user-guide/create-staging-app) - [Create Production App](https://docs.developer.singpass.gov.sg/docs/singpass-developer-portal-sdp/user-guide/create-production-app) ``` -------------------------------- ### Example ID Token Structure Source: https://docs.developer.singpass.gov.sg/docs/upcoming-changes/fapi-2.0-authentication-api/integration-guide/4 This JSON object represents a sample ID token, showcasing the various claims that can be present after decryption. It includes standard JWT claims like 'aud', 'iss', 'exp', 'iat', 'nonce', 'sub', and an example of the 'sub_account' claim. ```json { "aud" : "gnY6Erichpb5t4NFRP9R4L7aEC9N0FQH", "iss" : "https://id.singpass.gov.sg/fapi", "exp" : 1727322545, "iat" : 1727321945, "nonce" : "L5nmQfcetDDIeincoqvCrFyGv+nHobkv4XocNYPCXaQ=" "sub" : "1c0ee38-3a8f-4f8a-83bc-7a0e4c59d6a9", "sub_account": { "account_type": "SC/PR", "uinfin": "S1234567G" } } ``` -------------------------------- ### PKCE Parameters Source: https://docs.developer.singpass.gov.sg/docs/upcoming-changes/fapi-2.0-authentication-api/integration-guide/1 Parameters used for Proof of Key Code Exchange (PKCE) to protect authorization codes against misuse by malicious actors. These parameters are essential for implementing FAPI 2.0 compliant authentication. ```APIDOC ## PKCE Parameters ### Description Proof of Key Code Exchange (PKCE) parameters provide an additional security measure to protect authorization codes against misuse by malicious actors. These parameters are required for FAPI 2.0 compliant authentication flows. ### Parameters #### Query Parameters - **code_challenge** (string) - Required - The base64url encoded SHA256 hash of a randomly generated code_verifier. Must be a base64url-encoded string (note: base64url encoding differs from standard base64 encoding). - **code_challenge_method** (string) - Required - The method used to generate the code_challenge from the code_verifier. Only the value S256 is supported as mandated by FAPI 2.0 specifications. ### Parameter Details | Parameter | Description | Data Type | |-----------|-------------|----------| | code_challenge | The base64url encoded SHA256 hash of a randomly generated code_verifier | base64url-encoded string | | code_challenge_method | The method used to generate the code_challenge from the code_verifier | String (S256 only) | ### Request Example ``` GET /authorization?code_challenge=E9Mrozoa2owUednMg32c15count6O5T52mwQQ58754&code_challenge_method=S256 ``` ### Related Documentation Refer to the PKCE guide for understanding parameter generation and the code_challenge computation process. ``` -------------------------------- ### GET /userinfo Request with DPoP Header Source: https://docs.developer.singpass.gov.sg/docs/upcoming-changes/fapi-2.0-authentication-api/integration-guide/5 HTTP GET request to the /userinfo endpoint to retrieve user information. Requires DPoP header for proof of possession and Authorization header with DPoP-prefixed access token. The endpoint returns information only for scopes that were requested during the authorization request. ```http GET /userinfo HTTP/1.1 Host: id.singpass.gov.sg Authorization: DPoP eyJ0eXAiOiJhdCtqd3QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiJ1c2VyLWphbmUtZG9lIiwiYXVkIjoiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20vZGF0YSIsImV4cCI6MTc1NjczMDM4MCwiaWF0IjoxNzI1MTk0MzgwLCJqdGkiOiJ0eC0xMjMtYWJjIiwiY25mIjp7ImprdCI6Ik93SWlGaVl2T0NXRkpiV1hlbUdUZzRtU1NYQkNwZk9NaFhRV21XOTBVSEEifX0.dGhpcy1pcy1hLXBsYWNlaG9sZGVyLXNpZ25hdHVyZS1hcy1pdC1yZXF1aXJlcy1hLXByaXZhdGUta2V5 DPoP: eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3Arand0IiwiandrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiQXNWakh4elZ4MURaNnNKcEpzUnM2ek5YYXFmcFR3UmNfcXV0bWw0aEFJQSIsInkiOiI0SkhwVVZDRE5DaXhOTW9OclIzSElodFRzTWNfMF9NcmdpMzJxR3VoUkQ4In19.eyJqdGkiOiIyZmM3Y2Q4ZC0xN2IzLTRlYTUtYTg4ZC1lZWM0NTY5M2JhZDQiLCJodG0iOiJHRVQiLCJodHUiOiJodHRwczovL2lkLnNpbmdwYXNzLmdvdi5zZy91c2VyaW5mbyIsImlhdCI6MTc1NjcwODI0N30.wBYjFQRzY2o5aG82LjR1X8qT9bZ-jK3c7hI5fE0gP9vR_7sU6tW5xV4yZ3aB2cE1dF0eG9hI8jJ7kL6mN5oP4qR ``` -------------------------------- ### JWE Header Example Source: https://docs.developer.singpass.gov.sg/docs/technical-specifications/singpass-authentication-api/2.-token-endpoint/authorization-code-grant This JSON object represents an example of a JWE Header. It includes fields like 'kid' for key identification, 'cty' for content type, 'enc' for encryption algorithm, and 'alg' for key management algorithm. Relying parties should use the 'kid' field to select the correct decryption key. ```json { "kid": "client_01", "cty": "JWT", "enc": "A256CBC-HS512", "alg": "ECDH-ES+A256KW" } ``` -------------------------------- ### GET /userinfo Source: https://docs.developer.singpass.gov.sg/docs/upcoming-changes/fapi-2.0-authentication-api/migration-guides/myinfo-v4-apps The Userinfo Request endpoint retrieves user information. It replaces the previous Person API call and has a simplified request structure. ```APIDOC ## GET /userinfo ### Description This endpoint retrieves user information, serving as a replacement for the Myinfo Person API. It simplifies the request by removing the need for path parameters and query parameters. ### Method GET ### Endpoint /userinfo ### Parameters No path or query parameters are required for this endpoint. ### Request Example ```http GET /userinfo HTTP/1.1 Host: id.singpass.gov.sg Authorization: DPoP eyJ0eXAiOiJhdCtqd3QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiJ1c2VyLWphbmUtZG9lIiwiYXVkIjoiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20vZGF0YSIsImV4cCI6MTc1NjczMDM4MCwiaWF0IjoxNzI1MTk0MzgwLCJqdGkiOiJ0eC0xMjMtYWJjIiwiY25mIjp7ImprdCI6Ik93SWlGaVl2T0NXRkpiV1hlbUdUZzRtU1NYQkNwZk9NaFhRV21XOTBVSEEifX0.dGhpcy1pcy1hLXBsYWNlaG9sZGVyLXNpZ25hdHVyZS1hcy1pdC1yZXF1aXJlcy1hLXByaXZhdGUta2V5 DPoP: eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3Arand0IiwiandrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiQXNWakh4elZ4MURaNnNKcEpzUnM2ek5YYXFmcFR3UmNfcXV0bWw0aEFJQSIsInkiOiI0SkhwVVZDRE5DaXhOTW9OclIzSElodFRzTWNfMF9NcmdpMzJxR3VoUkQ4In19.eyJqdGkiOiIyZmM3Y2Q4ZC0xN2IzLTRlYTUtYTg4ZC1lZWM0NTY5M2JhZDQiLCJodG0iOiJHRVQiLCJodHUiOiJodHRwczovL2lkLnNpbmdwYXNzLmdvdi5zZy91c2VyaW5mbyIsImlhdCI6MTc1NjcwODI0N30.wBYjFQRzY2o5aG82LjR1X8qT9bZ-jK3c7hI5fE0gP9vR_7sU6tW5xV4yZ3aB2cE1dF0eG9hI8jJ7kL6mN5oP4qR ``` ### Response #### Success Response (200) - **person_info** (object) - Contains user data, nested within this field. - **uinfin** (object) - User's UINFIN details. - **lastupdated** (string) - The date the UINFIN was last updated. - **source** (string) - The source of the UINFIN data. - **classification** (string) - The classification of the UINFIN data. - **value** (string) - The UINFIN value. - **name** (object) - User's name details. - **lastupdated** (string) - The date the name was last updated. - **source** (string) - The source of the name data. - **classification** (string) - The classification of the name data. - **value** (string) - The name value. - **iss** (string) - The issuer of the token. - **sub** (string) - The subject (user identifier) of the token. - **aud** (string) - The audience of the token. - **iat** (integer) - The time the token was issued. #### Response Example ```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" } }, "iss": "https://id.singpass.gov.sg/fapi", "sub": "d45d8f21-6178-4713-b962-8635ed2a945a", "aud": "T5sM5a53Yaw3URyDEv2y9129CbElCN2F", "iat": 1746678089 } ``` ``` -------------------------------- ### Handling Redirects and Authentication Errors Source: https://docs.developer.singpass.gov.sg/docs/upcoming-changes/fapi-2.0-authentication-api/integration-guide/2 This endpoint describes how the system redirects users after authentication and the structure of potential error responses. ```APIDOC ## GET /redirect ### Description This endpoint is invoked via a redirect after a user attempts authentication with Singpass. It handles both successful and failed authentication scenarios by appending query parameters to the specified `redirect_uri`. ### Method GET ### Endpoint /redirect ### Query Parameters **For Failed Authentication:** - **error** (enum) - Required - An error code identifying the type of error that has occurred. Possible values: `invalid_request`, `invalid_request_uri`, `server_error`, `temporarily_unavailable`. - **error_description** (string) - Optional - A human-readable text description of the error. - **error_uri** (URL) - Optional - URI of a web page that includes additional information about the error. - **state** (string) - Required - The same state parameter passed in the authorization request. Must match the pattern `[A-Za-z0-9/+_-=.]+` and have a maximum length of 255 characters. ### Request Example ``` https://partner.gov.sg/redirect?error=invalid_request_uri&error_description=The%20request_uri%20provided%20is%20invalid&state=e32b9f28-5d34-4c0f-8b0e-6b670566c97f ``` ### Response #### Success Response (200) Upon successful authentication, the `redirect_uri` will be invoked without error parameters. Specific response fields depend on the subsequent application logic. #### Error Response (4xx/5xx based on context) If authentication fails, the redirect URI will include error parameters as detailed above, conforming to OIDC specifications. #### Response Example (Error) ```json { "error": "invalid_request_uri", "error_description": "The request_uri provided is invalid", "state": "e32b9f28-5d34-4c0f-8b0e-6b670566c97f" } ``` ### Error Handling Notes - If an authentication error response is received, display an appropriate error page to the user. Avoid displaying `error` or `error_description` verbatim to prevent content spoofing. - Interpret the `error` parameter to provide user-friendly guidance. ``` -------------------------------- ### GET /userinfo Source: https://docs.developer.singpass.gov.sg/docs/technical-specifications/singpass-authentication-api/3.-userinfo-endpoint/requesting-userinfo Retrieves UserInfo claims using a Bearer access token. The access token must be valid and contain the appropriate scopes. ```APIDOC ## GET /userinfo ### Description Clients must present a valid access token (of type `Bearer`) to retrieve the UserInfo claims. This access token is produced from the token endpoint. Only those claims that are scoped in the successful authentication request will be made available to the client. ### Method GET ### Endpoint /userinfo #### Query Parameters None #### Request Body None ### Request Example ```http GET /userinfo HTTP/1.1 Host: id.singpass.gov.sg Authorization: Bearer eyJhbGciOiJFUzI1NiIsInR5cCI6ImF0K2p3dCIsImtpZCI6ImFsaWFzL3ByZC1zcC1hdXRoLWFwaS1pZC10b2tlbi1zaWduaW5nLWtleS1rbXMtYXN5bW1ldHJpYy1rZXktYWxpYXMifQ.eyJzdWIiOiJzPVM2NTAwMDEwRSx1PWIyMGVhNjRhLTc2OTQtNDQyZi04Njc0LTRjMDVkNmQ5NDdmZiIsImNsaWVudF9pZCI6Ik9RYnNHU0NUNWRzUEhmUWdGbGlieUZud1g0YUpXYWlaIiwic2NvcGUiOiJvcGVuaWQgdWluZmluIG5hbWUgYmlydGhjb3VudHJ5IGRpYWxlY3QgZG9iIGhhbnl1cGlueWlubmFtZSBuYXRpb25hbGl0eSBwYXNzcG9ydGV4cGlyeWRhdGUgcGFzc3BvcnRudW1iZXIgcmFjZSByZXNpZGVudGlhbHN0YXR1cyBzZWNvbmRhcnlyYWNlIHNleCIsImp0aSI6ImF0LWJRTmEtT2FveEdvdXh3TTFiSmtsTU5leFNvSjJLOXJOcGdFS0wyb0ptcEEiLCJpYXQiOjE3Mjg2MjIxMTksImV4cCI6MTcyODYyMzkxOSwiYXVkIjoiaHR0cHM6Ly9pZC5zaW5ncGFzcy5nb3Yuc2cvdXNlcmluZm8iLCJpc3MiOiJodHRwczovL2lkLnNpbmdwYXNzLmdvdi5zZyJ9.3KjEQKXEhc88e6mRCv6sIe4U-psd1Pe4hLp7hQCN6MQGcHNFHpL8lmJ3B-RAxeunb-HKAxQLfSWnzpu767EQYQ ``` ### Response #### Success Response (200) - **response** (jwt) - The UserInfo claims, typically in JWT format. #### Response Example ```http HTTP/1.1 200 OK Content-Type: application/jwt; ``` ### Error Handling Singpass generally follows OIDC error response specifications. Refer to the Userinfo error response specifications for details. #### Error Response Example (401 Unauthorized) ```http HTTP/1.1 401 Unauthorized Date: Wed, 09 Oct 2024 10:49:52 GMT Content-Type: application/json; charset=utf-8 {"id":"afc64481-a01b-44c8-a716-52ef45c9c527","error":"invalid_token","error_description":"An error has occurred.","trace_id":"1-67065fd0-079db77d1f7a760e616f2271"} ``` **Note**: An access token is only valid for 30 minutes. Sending a request beyond its lifetime will result in an `invalid_token` error. ``` -------------------------------- ### GET /userinfo Source: https://docs.developer.singpass.gov.sg/docs/technical-specifications/singpass-authentication-api/3 Retrieves consented claims about the logged-in end-user. The claims are returned as a signed JSON Web Token (JWS) within a JSON Web Encrypted (JWE) token. ```APIDOC ## GET /userinfo ### Description This endpoint is a protected resource of the Singpass Authentication server where client applications can retrieve consented claims about the logged-in end-user. The claims are packaged in a signed JSON Web Token (JWS) within a JSON Web Encrypted (JWE) token, based on the scopes requested in the initial authentication request. ### Method GET ### Endpoint /userinfo ### Parameters #### Query Parameters - **access_token** (string) - Required - The access token obtained during the authorization code grant flow. ### Request Example ``` GET /userinfo?access_token=YOUR_ACCESS_TOKEN ``` ### Response #### Success Response (200) - **token** (string) - The JWE token containing the signed JWS with user claims. #### Response Example ```json { "token": "eyJ0eXAiOiJKV1QiLCJraWQiOiJ..." } ``` ```