Skip to content

Singpass login

Singpass login is only available to organisations that Singpass has onboarded as a relying party. Crow HR cannot do this for you, and Crow Tech does not hold a Singpass client you can share.

  • Your company applies through the Singpass developer documentation and portal and goes through Singpass’s own onboarding, review and testing. Eligibility, agreements, fees and timelines are set by Singpass and can change; read their current documentation before you start.
  • You register Crow HR as your application, with the redirect URI and JWKS URL that Crow HR shows after saving the provider (steps 1 and 2 below). Singpass requires HTTPS, so PUBLIC_URL must be your final HTTPS address.
  • Singpass issues you a client ID for staging and, after their checks, for production.
  • Pushed authorisation requests (PAR), PKCE, private_key_jwt client authentication and DPoP-bound tokens.
  • authentication_context_type=APP_AUTHENTICATION_DEFAULT on every request (Singpass requires it for Login apps; it matches the portal’s “General Authentication” scenario) and a client assertion with header typ: JWT.
  • If Singpass refuses the request, the test sign-in returns to Settings → Security with reason request_rejected, and Singpass’s error code (for example invalid_client or invalid_request) is in the audit log and the server log.
  • Decryption of the encrypted ID token with your relying-party key.
  • Keys: Crow HR generates an ES256 signing key and an ECDH-ES encryption key (P-256) and publishes the public halves at the provider’s JWKS URL. The API also accepts your own private JWKS instead. Private keys are encrypted at rest.
  • Default issuers are Singpass’s FAPI 2.0 endpoints: https://stg-id.singpass.gov.sg/fapi (staging) and https://id.singpass.gov.sg/fapi (production), checked against their live discovery documents on 9 Nov 2026. There is an optional override. The bare hosts without /fapi are Singpass’s older Login API, which has no PAR or DPoP, so don’t use them.
  • Scope openid only. Crow HR stores the Singpass UUID from the subject, never the NRIC. There is no Myinfo data retrieval.
  1. In Settings → Security choose Add a method → Singpass. Choose Staging and leave the issuer override empty unless Singpass tells you otherwise. Leave the client ID empty: Singpass only issues it after you register the redirect URI and keys. Save. Crow HR generates the relying-party keys and shows the two values for the next step. Until it has a client ID, Singpass stays off and the sign-in page doesn’t show it.

  2. In the Singpass Developer Portal, create a Login app in Staging (authentication scenario “General Authentication”) and enter the Redirect URI (<PUBLIC_URL>/api/v1/auth/oidc/<provider id>/callback) and the JWKS URL (<PUBLIC_URL>/api/v1/auth/oidc/<provider id>/jwks.json). Keep the scopes to OpenID only. A staging app is active as soon as you submit it; its App ID is the client ID. Edit the method in Crow HR and add it.

    Singpass fetches the JWKS URL from its own servers (on AWS). If your server is behind Cloudflare with Bot Fight Mode on (or another bot filter), that fetch gets a challenge page and Singpass answers Crow HR’s sign-in request with HTTP 502. On Cloudflare’s Free plan Bot Fight Mode can’t be skipped for one path. Either turn it off for that zone, or choose JWKS object in the portal and paste the contents of the JWKS URL (public keys only). With a JWKS object, paste the keys again whenever you replace them in Crow HR.

  3. Create a staging test account in the portal (your app → Test account → Create; up to 5 per app; the password is behind the eye icon). Then run Test sign-in in Crow HR and choose Use password on the Singpass staging page. Settings → Security asks for this test until it passes, then shows when it passed. If Singpass refuses the request, the test returns with reason request_rejected and the details are in the audit log.

  4. Only after a successful staging test and Singpass’s approval, edit the provider, switch the environment to Production with the production client ID, test again, and switch it on.

Until the provider has a client ID and keys, the sign-in page shows no Singpass button and Settings → Security shows Singpass as not configured.

Singpass accounts are never linked by email or NRIC. A member is linked to their Singpass identity only:

  • by choosing the Singpass button on their invitation page; or
  • by signing in another way and linking Singpass in My sessions → Linked sign-in methods.

Just-in-time account creation is not available for Singpass.

Singpass’s button design specification (effective 1 September 2026) requires the official Singpass logo inside the button. Singpass publishes the logo for its partners, not under a licence that allows redistribution in an MIT repository, so Crow HR does not bundle it. As a Singpass partner, you add it yourself:

  1. Download the Singpass logo from the button specification page (the “Download Singpass logo” file). Use the full-colour logo for the default white button.

  2. Save it as branding/singpass-logo.svg (or .png, at most 200 KB) in the app’s data volume, for example:

    Terminal window
    docker compose exec app mkdir -p /data/branding
    docker compose cp singpass-logo.svg app:/data/branding/singpass-logo.svg
  3. Reload the sign-in page: the Singpass button now shows the logo. No restart is needed. Crow HR serves the file at /branding/singpass-logo as an image only (an SVG cannot run script).

Without the file, the button shows the plain text “Log in with Singpass”. Do not go live with Singpass until the button shows the official logo.

Crow Tech’s public demo runs entirely in the visitor’s browser, so it cannot hold Singpass keys. To let demo visitors log in with Singpass for real, a Crow HR server acts as the relying party for it:

  1. On that server, add a Singpass method as above (in its own organisation) and register it with Singpass. It does not need to be switched on.
  2. Set DEMO_SINGPASS_PROVIDER_ID (the method’s id, as in its redirect URI) and DEMO_SINGPASS_RETURN_URL (the demo’s sign-in page, for example https://hr.crow.sg/sign-in/kopi-kaki) and restart.
  3. Build the demo with VITE_DEMO_SINGPASS_START_URL=<server>/api/v1/auth/oidc/<id>/start?purpose=demo and, for the logo, VITE_SINGPASS_LOGO_SRC.

The visitor logs in with Singpass, the server checks Singpass’s answer and then forgets the person: no account, session, link or Singpass ID is stored (the audit log records only that a demo login happened). Back in the demo, they choose HR admin or Employee and look around their own fictional copy. Each network can start 20 demo logins an hour and the server 1,000 a day; Singpass Login is free for the first 50,000 logins a month per UEN. Real visitors need a production Singpass app; Singpass staging accepts only its test accounts.

Item State
FAPI 2.0 flow against the mock identity provider Tested (packages/core/src/auth/singpass.test.ts, oidc-flow.http.test.ts)
Sign-in against Singpass staging Passed 9 Nov 2026: owner test sign-in on a staging server (Cloudflare Tunnel and Traefik in front) with a Singpass staging test account and password login. PAR with DPoP, private_key_jwt, authentication_context_type, token exchange and the encrypted ID token all worked against https://stg-id.singpass.gov.sg/fapi. The JWKS was given as a JWKS object (see step 2).
Production Not verified
Official logo in the button Not bundled