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. For this integration, we treated 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 terminated. 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.
Patching Fails on the SME HR Portal

We migrated a local SME HR onboarding portal last month. The portal used Myinfo v3 to pre-fill employee identity and work-pass fields during onboarding. The first engineering instinct was 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.
We tried that. It held for about two days of testing.
The failure mode was predictable in retrospect. The middleware held the DPoP state: the RSA key pair, the token binding, the signed JWT construction logic. The form builder held the session state: step position, validated fields, last-touch timestamp. These two states diverged constantly. A user who paused at step three and returned six minutes later triggered a session refresh. The form builder refreshed its session cookie; the middleware’s DPoP state, keyed to the original session, became orphaned. The signed JWT it constructed on retry referenced a key pair the Singpass endpoint no longer recognized as bound to the current token. Request denied.
Over a two-week testing period covering 2,000 completed form sessions, this desync produced ten hard failures — a 0.5 percent rate — where the Singpass endpoint rejected the DPoP-bound retry outright. (Source: wGrow UAT logs, two-week test window, n=2,000 completed sessions.) For an HR onboarding flow, that’s not a rounding error. We stripped the static token logic entirely and started over.
Deploying a Localized State Agent
The fix was conceptually simple once we admitted the middleware model was wrong: stop treating authentication state as middleware and start treating it as agent state.
We deployed a localized Python 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. After the architecture switch, we saw zero token-desync failures across 1,840 sessions in a three-week post-deployment monitoring window. (Source: wGrow post-deployment telemetry, three-week monitoring window, n=1,840 sessions.) The form builder regression suite required no changes. We touched zero frontend code.
Scaling to the Corporate Grant Pipeline

- Token desyncs
- 0
- Regression time
- -60%
- Client crypto
- None
We replicated the same pattern for 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.
The initial concern was whether a single-session agent model could 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 decoupled frontend and backend release cycles in a way we hadn’t fully anticipated. Previously, any authentication protocol change required coordinated deploys across the grant form UI and the API integration layer. Now the agent owns the protocol layer entirely. Frontend engineers interact only with a stable internal REST contract. When a minor Myinfo Business endpoint parameter changed mid-project, the agent absorbed the change in a single file — no frontend regression cycle. On this grant-pipeline migration, that separation eliminated the full UI regression cycle; frontend engineers validated only the internal REST contract.
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 failed us 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.