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
This guide applies only to existing Myinfo Business (v1/v2) partners whose Myinfo Business application retrieves individual information using the legacy Myinfo v3 APIs.
Specifically, this guide applies if your application currently uses the following endpoints:
If your integration uses these endpoints, this guide explains how to migrate your individual retrieval flow to Myinfo (v5) using OpenID Connect (OIDC) and the FAPI 2.0 Security Profile.
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.
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.
Create a new Myinfo (v5) app on the Singpass Developer Portal. Create a staging app for testing, then a production app for go-live.
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.
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).
Register HTTPS redirect URIs. Only
https://URLs are accepted β see Replace custom scheme URLs for mobile apps.Map your attributes to v5 scopes. Translate your current
attributeslist 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
DPoPheader β a JWT containing the HTTP method (htm), target URI (htu), a uniquejtiandiatβ 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):
Implement app-claimed HTTPS URLs β Android App Links or iOS Universal Links.
Register the new HTTPS URLs in the Developer Portal.
In the authorization request, set
redirect_uri/app_launch_urlto the new HTTPS URLs and addredirect_uri_https_type=app_claimed_https.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:
Send a server-to-server
POSTto thepushed_authorization_request_endpoint(published in Singpass's OpenID configuration), with anapplication/x-www-form-urlencodedbody and a DPoP header. This returns a short-livedrequest_uri.Redirect the browser to the authorization endpoint with only two query parameters:
client_idandrequest_uri.
Parameter changes in the authorization request:
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:
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:
Decrypt the ID token with your JWKS encryption private key.
Verify the inner JWS signature against Singpass's published JWKS.
Validate the
iss,aud(yourclient_id),expclaims, and confirmnoncematches the value sent in Step 1.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:
Remove
subfrom the path. The endpoint identifies the user from the token; you no longer parse the access token to build the URL.Remove the PKI signature. Authentication is via DPoP + the access token only.
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.Change the token prefix from
BearertoDPoP.Include the
DPoPproof 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_SIGNbase-string construction and RSA-SHA256 request-signing codeX.509 certificate management for API request signing
client_secretstorage and rotation for the person flowAccess-token parsing used to extract
subfor the Person API pathCustom scheme URL handling (mobile)
The v3 app registration itself, after Singpass confirms deactivation
Keep your JWE/JWS decryption utilities β you will repurpose the concept (with new keys and algorithms) for ID token decryption, and your Myinfo Business Entity-Person flow still uses payload decryption per the biz v2 spec.
Migration checklist
Onboarding
Build
Test (staging)
Cutover
Common pitfalls
Reusing the v3 app or credentials β a new v5 app is mandatory; the old
client_idwill not work.Sending
purposein the request β it now lives in the portal config.Comma-separated scopes β the v5
scopeis space-separated and must includeopenid.Missing the DPoP header on PAR or userinfo β DPoP is required on all three calls, not just token exchange.
Using
Beareron userinfo β the prefix must beDPoP.Parsing the access token for
subβ treat it as opaque; read the UUID from the ID token.Reading person data from the response root β it is now under
person_info.JWKS with only one key β you need both a signing key and an encryption key.
Custom scheme redirect URLs β rejected; mobile apps must use app-claimed HTTPS.
References
Last updated
Was this helpful?