Singpass Myinfo v5 and FAPI 2.0: An Agentic UI Upgrade
By wGrow Project Team ·
Static bearer tokens have no place in a Myinfo v5 integration. Full stop.
If your intake pipeline still relies on a long-lived OAuth 2.0 bearer token against Singpass, a single intercepted request opens the door to credential replay. That’s the security reality. The compliance reality is that you’re now four months from a hard wall: the NDI API deprecation schedule published by GovTech sets Myinfo v3 decommissioning for September 2026. [S1] The replacement, Myinfo v5, enforces Financial-grade API 2.0 (FAPI 2.0) and Demonstrating Proof-of-Possession (DPoP) tokens.
These are not the same security model. The gap between them is architectural, not cosmetic.
The FAPI 2.0 Cryptographic Reality
Standard OAuth 2.0 is built on bearer tokens — a string that grants access to whoever holds it. If it leaks, the attacker has full access until expiry. No questions asked. FAPI 2.0 closes that hole by binding the access token cryptographically to the specific client that requested it. FAPI 2.0 permits two mechanisms for sender-constrained tokens: DPoP and mTLS; Myinfo v5 uses DPoP. With DPoP, the client generates an RSA or EC key pair per session; the public key (JWK) is embedded in the header of each DPoP proof JWT, and the server binds the issued access token to a thumbprint of that key. The client signs every subsequent API call with a fresh DPoP proof derived from the session’s private key.
A DPoP proof is a signed JWT containing the HTTP method, the request URI, and a timestamp to prevent replay. The spec is well-defined. What matters operationally is where the key pair must live and how long it persists. A sound design treats the DPoP private key as ephemeral: generated in-memory at session start, retained only for the duration of the API interaction, and destroyed when the session terminates. That approach keeps proof-of-possession material from becoming another long-lived secret to rotate and protect.
Traditional form builders are not designed for this. They pass tokens. They do not generate cryptographic artifacts. The Singpass developer guide for v5 is explicit: each protected-resource request must carry a freshly generated DPoP proof. [S2] For any pipeline that still abstracts authentication as “get a token, attach it to the header,” this is a rebuild. Not a patch.
Why Patching Fails on a Legacy Form Portal

Suppose a team has an HR onboarding portal that uses Myinfo v3 to pre-fill employee identity and work-pass fields. The first engineering instinct is to write a middleware shim — keep the existing form builder, inject a new authentication layer behind it, translate v5 responses into something the old form state logic could consume.
That approach can survive a first round of testing.
The failure mode is predictable. The middleware holds the DPoP state: the RSA key pair, the token binding, the signed JWT construction logic. The form builder holds the session state: step position, validated fields, last-touch timestamp. These two states diverge constantly. A user who pauses at step three and returns minutes later triggers a session refresh. The form builder refreshes its session cookie; the middleware’s DPoP state, keyed to the original session, becomes orphaned. The signed JWT it constructs on retry references a key pair the Singpass endpoint no longer recognizes as bound to the current token. Request denied.
Even if this desync produces only occasional hard failures, where the Singpass endpoint rejects the DPoP-bound retry outright, that is not a rounding error for an HR onboarding flow. The static token logic has to go entirely, and the design has to start over.
Deploying a Localized State Agent
The fix is conceptually simple once the middleware model is recognized as wrong: stop treating authentication state as middleware and start treating it as agent state.
Deploy a localized background agent sitting strictly between the form builder and the Singpass API endpoint — not a gateway, not a proxy, but a stateful process with one job: own the full FAPI 2.0 cryptographic lifecycle for each active user session.
When a user initiates a Myinfo login, the agent generates the RSA key pair dynamically in memory. It handles the Singpass authorization code exchange, constructs the DPoP-bound access token request, and builds the signed JWT for the DPoP header on every outbound API call. The form builder knows none of this. It sends a request to an internal REST endpoint, gets back a simplified session token, and renders pre-filled form fields. The FAPI 2.0 handshake is entirely opaque to the UI layer.
The agent also handles lifecycle events the middleware had no clean answer for: session expiry, network retry with fresh DPoP proofs, deterministic key destruction on logout. The private key never touches the form builder process.
There is an infrastructure tradeoff — the agent must be highly available, and a crash requires clean session recovery. A process supervisor (systemd, PM2, or a container restart policy) brings the agent back up, but in-memory DPoP state does not survive the restart. Sessions active at the time of the crash must be explicitly expired, and affected users go through a fresh authorization code exchange on next access. That recovery path needs to be defined explicitly in the runbook before you go to production. With this architecture, token desync between the two state holders is designed out. The form builder regression suite should need no changes, because no frontend code is touched.
Scaling to a Multi-Session Grant Pipeline

- UI coupling
- Zero
- Client crypto
- None
The same pattern extends to a corporate grant application pipeline. The workload is heavier: fetching Myinfo Business data means larger payloads, variable API latency from upstream data sources, and a user flow that spans multiple sessions across days rather than a single onboarding event.
A natural concern is whether a single-session agent model can generalize to multi-session workflows. It can. The agent maintains a session manifest — which DPoP key pairs are active, when they were generated, which API interactions they’ve been used for, when they expire. When a grant application resumes the next morning, the agent detects the expired key pair, initiates a fresh authorization code exchange, and issues a new DPoP-bound token before the form builder makes its first data request. From the user’s perspective, the form simply loads.
Isolating DPoP state in the agent also decouples frontend and backend release cycles. Without it, any authentication protocol change requires coordinated deploys across the grant form UI and the API integration layer. With it, the agent owns the protocol layer entirely. Frontend engineers interact only with a stable internal REST contract. When a minor Myinfo Business endpoint parameter changes, the agent can absorb the change in a single file — no frontend regression cycle.
Compliance as an Architectural Forcing Function
The September 2026 deadline is fixed. The published NDI deprecation schedule lists Myinfo v3 decommissioning for September 2026. [S1]
But the real point isn’t the deadline. It’s what the deadline exposes: how brittle authentication logic becomes when it’s coupled to presentation state. That coupling is what fails in the middleware approach. It’s what will fail any team that treats FAPI 2.0 as a patch job.
Government API specifications will keep moving toward stricter financial-grade security models. FAPI 2.0 is the current standard; the OpenID Foundation’s FAPI working group is actively developing the specification, and successive iterations will introduce further constraints. Every time a new cryptographic requirement lands, any architecture that conflates authentication state with session state faces a partial rebuild.
The pattern that survives this churn is straightforward: deploy a localized agent to own cryptographic state, expose a stable internal REST contract to the UI layer, and treat every government API migration as a backend concern. September 2026 is a forcing function. The architecture it forces is worth keeping long after the deadline passes.