For departments · integration guide (concept)
Add the national sign-in in an afternoon.
One block of markup, one OpenID Connect callback, one line that declares how sure you need to be for each action. Your own login stays exactly where it is — and comes back on its own if the hub is ever busy.
It looks like yours, because it is yours
The maker of this prototype, Sambit Swarup, chose the design language your portal already runs over a custom look. So the button, the consent screen and the account are your own contracts with six classes added, built from your own tokens. Your citizens see the chrome they already trust; your team pastes markup instead of running a redesign; accessibility comes with it.
Quickstart — six steps to “Meri Pehchaan Ready”
- Register your service. Name, logo, redirect URIs, back-channel logout URI, and the scopes you will ask for. That name and logo are what the citizen sees on the consent screen — they are the contract.
- Get sandbox keys. A client id and secret that work only against this sandbox. Nothing here touches a live system.
- Drop the button in. First in your form's action area, alone, full width. Your existing form goes under “Other ways to sign in” — collapsed, never removed.
- Point your callback at the hub. Standard authorization-code + PKCE. Verify the id_token against the published JWKS. Read
acr. - Declare assurance per action. Viewing is Shabda, filing is Anumaan, signing is Pratyaksh. Ask for step-up in place; never send the citizen away.
- Pass conformance, go live. The checklist at the bottom of this page is the badge. The sandbox faults are the exam.
The button kit
Verb only, one language at a time, the Pehchaan Chakra on the left. Twelve languages switch with the page. Never “Login with”, never “Powered by”, never a provider's name on it.
Default · degraded (the hub is busy; your own login is shown below it)
<button class="ux4g-btn-meripehchaan ux4g-btn-lg ux4g-w-100" type="button" data-action="portal-signin">
<svg class="ux4g-btn-icon" aria-hidden="true"><use href="/design/mark/pehchaan-chakra.svg#mark"/></svg>
<span data-verb="signin" lang="en">Sign in</span>
</button>The OpenID Connect contract — read live from the hub
This table is not typed in. It is /.well-known/openid-configuration, fetched by this page when you opened it.
| Field | Value |
|---|---|
| issuer | fetching… |
// Node (Hono) — the callback your portal already has, pointed at the hub
const tokens = await fetch(discovery.token_endpoint, { method: "POST",
body: new URLSearchParams({ grant_type: "authorization_code", code, redirect_uri,
client_id, client_secret, code_verifier }) }).then(r => r.json());
const { payload } = await jwtVerify(tokens.id_token, JWKS, { issuer, audience: client_id });
// payload.acr → "mp:shabda" | "mp:anumaan" | "mp:pratyaksh"; payload.mp_adhikrit → roles
session.create({ sub: payload.sub, name: payload.name, acr: payload.acr, sid: payload.sid });- Authorization code with PKCE (S256) is mandatory; codes are single-use and live 60 seconds.
- Refresh tokens rotate. Token exchange (RFC 8693) carries a delegated
actclaim for helpers acting under a grant. - Revocation (RFC 7009), introspection (RFC 7662) and back-channel logout are all live in this sandbox.
- Wire paths mirror the published DigiLocker partner API (
/public/oauth2/1/authorize,/public/oauth2/2/token,/public/oauth2/1/user) so an existing integration changes one hostname. - Page translation is mapped to Bhashini, the national language platform, through its published pipeline API (config, then compute, translation task) under the department's own key. Twelve languages ship as page strings; the rail is switched off in this sandbox and nothing here calls the live service.
Assurance per action
Send acr_values for what the action needs, not for what the portal wants in general. The hub steps up in place; the citizen never leaves your page.
| Action | Minimum tier | Proven by |
|---|---|---|
| View status, track an application | शब्दShabda | Something you know or hold — mobile OTP |
| File, apply, submit a form | अनुमानAnumaan | Records — OTP to the registered number plus a linked account |
| Cancel, withdraw, revise money in motion; sign | प्रत्यक्षPratyaksh | The person — passkey or phone approval with number matching |
| Act for someone else | अधिकृतAdhikrit | Pratyaksh plus a registered role and a grant approved by the citizen |
The request parameters, by their published names
Meri Pehchaan 1.0's Requester specification v2.3 (September 2023, on API Setu) already defines these. The hub honours every one under the same name, so a portal integrated with 1.0 sends what it sends today. Live rail
| Parameter | Values | What the citizen sees |
|---|---|---|
purpose | kyc · verification · compliance · availing_services · educational | printed on the consent screen |
consent_valid_till | UNIX seconds; the citizen may shorten it | printed, and shortened by the citizen |
req_doctype | PANCR, DRVLC, UNCRD … | only those documents appear on the consent screen |
acr | pan · aadhaar · driving_licence, or mp:shabda · mp:anumaan · mp:pratyaksh | a minimum tier for the sign-in; the token says which was reached |
amr | space-separated methods, with dl_flow=signup | sign-up hint |
pla · plsignup · ulsignup | Y | PIN-less and username-less flows |
dl_flow · verified_mobile | signup · a mobile you already verified | the hub skips the code you already sent |
What 2.0 adds to the token, and 1.0 does not carry: acr, amr, sid, nonce, auth_time; discovery and JWKS; back-channel logout. Proposed
Every consent receipt is written in the API Setu consent-artefact schema (consentId, dataConsumer, dataProvider, purpose, user, data, permission, signature) and every NSSO Consent API operation has an alias under its published name. Spec files are public at cf-media.api-setu.in/specfiles/. Live rail
Sandbox — break it before a citizen does
These switches change the live hub behind this site. Turn one on, then walk the sign-in. hub_down is the exam: your portal must show its own login and keep every open session.
- hub_down — discovery, JWKS and authorize answer 503; portal sessions keep serving
- idp_down — the routed identity provider is unavailable; the hub offers another identifier
- otp_delay — the OTP gateway is slow; the resend timer earns its keep
- otp_peak — the gateway is at capacity (429 with retry-after)
- dup_account — two accounts match the identifier; the citizen chooses
- clock_skew — the hub's clock is off; token validation must tolerate it
Hub status as your portal sees it: checking…
Three ways to join, matched to how your portal is run
“Meri Pehchaan Ready” — the checklist behind the badge
- checkThe button is first, alone and full width; the department's own login is one tap away, never removed
- checkConsent is shown by the hub before the redirect; the portal asks only for scopes it registered
- check
acris read on every callback and every step-up; signing actions demand Pratyaksh - checkWith
hub_downon, the portal still signs in the old way and no open session is lost - checkBack-channel logout ends the portal session within 30 seconds of “Sign out everywhere”
- checkActions taken under a grant are logged as “helper, for citizen, under grant”
A concept badge, awarded by nobody. The list is the point; the reference architecture, adapter tiers and migration waves are in the repository's docs/03.