For the complete documentation index, see llms.txt. This page is also available as Markdown.

Myinfo Business (v1/v2) Person v3 flows

Migration guide for Myinfo Business (v1/v2) partners whose applications use the legacy Myinfo v3 APIs to retrieve individual information.

Who this guide is for

Endpoint
Purpose

GET /com/v3/authorise

Authenticate the user and obtain consent

POST /com/v3/token

Exchange the authorisation code for an access token

GET /com/v3/person/{sub}

Retrieve the individual's Myinfo information

What is not covered

This guide covers only the migration of the individual information retrieval flow.

It does not cover the migration of Myinfo Business entity APIs, including endpoints such as:

  • GET /biz/v2/entity-person/{uen}/{uuid}

  • Other Myinfo Business entity APIs

If your application uses these APIs, refer to the Myinfo Business (v1/v2) to v3 (FAPI 2.0) Migration Guide. The entity retrieval flow has its own migration path and should be migrated separately.

If your application uses both the legacy Myinfo Person APIs and the Myinfo Business entity APIs, you will need to follow both migration guides.

Overview

Some Myinfo Business partners use their Myinfo Business application to retrieve both:

  • Business entity information through the Myinfo Business APIs.

  • Individual information through the legacy Myinfo Person APIs.

These two retrieval flows are independent and have separate migration paths.

This guide covers only the migration of the individual information retrieval flow from the legacy Myinfo v3 APIs to Myinfo (v5).

Because the Myinfo (v5) security model differs significantly from the legacy implementation, you must onboard a new Myinfo (v5) application and obtain a new client ID. Existing Myinfo v3 applications and credentials cannot be reused. Given these changes, Singpass recommends implementing the new flow using a certified OpenID Connect Relying Party library instead of modifying your existing Myinfo Business v1/v2 integration.

The table below summarises the key differences between the legacy and new implementations.

Legacy mechanism (v1 / v2 / v3)
New mechanism (v5 / FAPI 2.0)

Authorization request via browser redirect with query parameters

Pushed Authorization Request (PAR) β€” RFC 9126

PKI_SIGN request signing (RSA signature over a base string) with X.509 certificates

Client assertion (private_key_jwt) + JWKS

client_secret in the token request

Client assertion (no shared secret)

Bearer access tokens

DPoP-bound authorization codes & access tokens

No PKCE

PKCE (S256) β€” mandatory

Person API: GET /com/v3/person/{sub}?attributes=…

GET /userinfo (no path or query parameters)

Access token only

Access token + encrypted ID token (must be decrypted and verified)

Before you start: create a new Myinfo (v5) app

Your existing Myinfo v3 credentials β€” client_id, client_secret, APP ID and PKI certificates β€” cannot be reused. Complete onboarding first.

  1. Create a new Myinfo (v5) app on the Singpass Developer Portal. Create a staging app for testing, then a production app for go-live.

  2. One purpose per app. Myinfo (v5) apps must have a single purpose. If your current v3 app serves multiple purposes, create one v5 app per purpose. The purpose is now configured in the portal and is no longer sent in each request.

  3. Configure a JWKS (JSON Web Key Set) instead of uploading an X.509 certificate. Your JWKS must contain at least one signing key (for client assertions) and one encryption key (so Singpass can encrypt the ID token to you).

  4. Register HTTPS redirect URIs. Only https:// URLs are accepted β€” see Replace custom scheme URLs for mobile apps.

  5. Map your attributes to v5 scopes. Translate your current attributes list into the equivalent scopes from the Singpass Data Catalog, and confirm the scopes allowed for your app during onboarding.

General changes

These apply across the whole flow.

Implement DPoP (Demonstrating Proof of Possession)

DPoP binds your authorization code and access token to an ephemeral private key known only to you, so a stolen code or token cannot be replayed by another party.

Your application must:

  • Generate an ephemeral EC key pair (e.g. P-256) per authentication flow.

  • Attach a signed DPoP header β€” a JWT containing the HTTP method (htm), target URI (htu), a unique jti and iat β€” to the pushed authorization request, the token request, and the userinfo request.

  • Reuse the same key pair for all three calls in a single flow so the token stays bound to it.

See the DPoP guide for the exact JWT structure.

Replace custom scheme URLs (mobile apps only)

The new API does not support custom scheme URLs (anything that does not start with https://) as redirect or app-launch URLs.

If your Android/iOS app currently uses a custom scheme (e.g. myapp://callback):

  1. Implement app-claimed HTTPS URLs β€” Android App Links or iOS Universal Links.

  2. Register the new HTTPS URLs in the Developer Portal.

  3. In the authorization request, set redirect_uri / app_launch_url to the new HTTPS URLs and add redirect_uri_https_type=app_claimed_https.

  4. After deployment, remove the old custom-scheme URLs from your app configuration.

Note the rename: appLaunchURL β†’ app_launch_url, which must be pre-registered in the portal.

Step-by-step flow changes

Step 1 β€” Authorization request: redirect β†’ Pushed Authorization Request

Old (v3): your webpage redirected the browser to the authorise endpoint with all parameters in the query string.

New (v5): two sub-steps:

  1. Send a server-to-server POST to the pushed_authorization_request_endpoint (published in Singpass's OpenID configuration), with an application/x-www-form-urlencoded body and a DPoP header. This returns a short-lived request_uri.

  2. Redirect the browser to the authorization endpoint with only two query parameters: client_id and request_uri.

Parameter changes in the authorization request:

Change
Detail

Remove authmode

No longer used

Remove purpose

Configured per app in the Developer Portal

Remove login_type

No longer used

Rename attributes β†’ scope

Change from comma-separated to space-separated, and prepend openid. Old: name,hanyupinyinname β†’ New: openid name hanyupinyinname

Rename appLaunchURL β†’ app_launch_url

Must be pre-registered (mobile)

Add PKCE

code_challenge (base64url SHA-256 of your code_verifier) and code_challenge_method=S256

Add nonce

A unique, unguessable value per request; echoed back in the ID token and must be verified

Keep state, redirect_uri, client_id, response_type=code

state still protects against CSRF and reconciles the callback

Step 2 β€” Callback handling

Conceptually unchanged: the user is redirected to your redirect_uri with code and state. Continue to verify that state matches the value you sent. Error callbacks (error, error_description) still apply.

Step 3 β€” Token exchange

Old (v3): POST /token with a PKI_SIGN Authorization header, plus client_secret, client_id, code, redirect_uri, grant_type and state in the body.

New (v5): POST to the token endpoint with these changes:

Change
Detail

Remove the Authorization: PKI_SIGN … header

No more base-string request signing

Remove client_secret

Replaced by client assertion

Remove state

Not supported in the token request body

Add client_assertion + client_assertion_type

client_assertion is a JWT signed with your JWKS signing key; client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer

Add code_verifier

The same verifier used to derive code_challenge in Step 1 (PKCE)

Add DPoP header

Same key pair as used for the PAR

New β€” handling the ID token. The token response now returns an encrypted ID token alongside the access token. You must:

  1. Decrypt the ID token with your JWKS encryption private key.

  2. Verify the inner JWS signature against Singpass's published JWKS.

  3. Validate the iss, aud (your client_id), exp claims, and confirm nonce matches the value sent in Step 1.

  4. If you need the user's UUID (sub), read it from the ID token β€” do not parse the access token.

The access token has a lifetime of 30 minutes.

Step 4 β€” Person data retrieval: Person API β†’ Userinfo

This is the core change for your team.

Old β€” Myinfo v3 Person API:

New β€” Myinfo v5 Userinfo:

Required changes:

  1. Remove sub from the path. The endpoint identifies the user from the token; you no longer parse the access token to build the URL.

  2. Remove the PKI signature. Authentication is via DPoP + the access token only.

  3. Remove all query parameters (attributes, client_id, txnNo). All data for the scopes requested in Step 1 is returned β€” the request carries no attribute list.

  4. Change the token prefix from Bearer to DPoP.

  5. Include the DPoP proof header.

Step 5 β€” Parsing the userinfo response

The format of each attribute is unchanged from the Person API (same value / code+desc / source / classification / lastupdated structure your parsers already handle). The only difference is that person data is now nested inside a person_info field, alongside standard OIDC claims.

Action: point your existing parsing logic at response.person_info instead of the response root. Your downstream mapping should otherwise be reusable.

What you can decommission after cutover

Once the v5 flow is live and the v3 flow is retired:

  • PKI_SIGN base-string construction and RSA-SHA256 request-signing code

  • X.509 certificate management for API request signing

  • client_secret storage and rotation for the person flow

  • Access-token parsing used to extract sub for the Person API path

  • Custom scheme URL handling (mobile)

  • The v3 app registration itself, after Singpass confirms deactivation

Migration checklist

Onboarding

Build

Test (staging)

Cutover

Common pitfalls

  1. Reusing the v3 app or credentials β€” a new v5 app is mandatory; the old client_id will not work.

  2. Sending purpose in the request β€” it now lives in the portal config.

  3. Comma-separated scopes β€” the v5 scope is space-separated and must include openid.

  4. Missing the DPoP header on PAR or userinfo β€” DPoP is required on all three calls, not just token exchange.

  5. Using Bearer on userinfo β€” the prefix must be DPoP.

  6. Parsing the access token for sub β€” treat it as opaque; read the UUID from the ID token.

  7. Reading person data from the response root β€” it is now under person_info.

  8. JWKS with only one key β€” you need both a signing key and an encryption key.

  9. Custom scheme redirect URLs β€” rejected; mobile apps must use app-claimed HTTPS.

References

Last updated

Was this helpful?