DigiLocker API Integration: Step-by-Step Guide
No more blurry PDF uploads. DigiLocker is the fastest way to verify a user's real, government-issued documents in India, and the document comes signed at source so you can actually trust it. Below we go end to end: getting access, running the OAuth consent redirect, listing a user's issued documents, and pulling a signed copy. If you've wired up an OAuth flow before but never touched DigiLocker, you're the reader we wrote this for.
We'll stick to the real, public DigiLocker flow as documented on apisetu.gov.in. Where it helps, we'll note how NamoID puts this behind one OIDC issuer so you don't hand-roll token storage and consent logging yourself.
What DigiLocker is and how to get access
DigiLocker is a flagship Digital India service run by the Ministry of Electronics and Information Technology (MeitY). It gives every citizen a cloud locker tied to their Aadhaar number, holding documents that issuers like the Income Tax Department, transport authorities, and education boards push directly. Because those documents are issued and signed at source, a document fetched from DigiLocker carries the same legal standing as the original. That is the whole point: you stop trusting a user-uploaded scan and start trusting a signed record from the issuer.
For your app, DigiLocker exposes two API families through API Setu:
- Issuer APIs, used by organisations that issue documents into citizens' lockers.
- Requester APIs, used by apps like yours that want to read a user's documents, with the user's consent.
You almost certainly want the Requester side. The integration is a standard OAuth 2.0 authorization-code flow. The user signs in to DigiLocker, consents at the document or scope level, and you receive an access token you can exchange for their issued-documents list and the document files themselves. The user is always in the loop, and consent is granted per document or per scope, so you never get blanket access to someone's locker.
To get started you need to onboard as a partner. Sign up on the API Setu partners portal, register your organisation, and request access to the DigiLocker Requester APIs. Onboarding involves identity and purpose checks, because you are asking for access to citizens' verified records. Budget real calendar time here. The technical work is a day. The approval and KYC of your own organisation is the long pole.
This is general engineering information and not legal advice. If your use of DigiLocker data touches lending, KYC for regulated entities, or storage of identity data, get your compliance counsel involved early.
Getting client credentials (sandbox to prod)
Once your organisation is approved as a Requester, you create OAuth 2.0 credentials in the partner portal. In the API Setu console you go to the DigiLocker Requester configuration, create an OAuth client, and you are issued a client ID and client secret. You also register one or more redirect URIs and can customise the branding shown on the user consent screen.
A few things to get right up front:
- Treat the client secret like a private key. It belongs in a secrets manager or environment variable on your backend, never in your frontend bundle, mobile app, or git history.
- Register exact redirect URIs. DigiLocker, like any sane OAuth server, only redirects back to URIs you pre-registered. A trailing-slash mismatch will fail the flow.
- Use separate credentials per environment. DigiLocker provides a sandbox so you can test the full flow with test users before touching real lockers. Keep sandbox and production client IDs in different config so a test build can never hit prod.
Promotion from sandbox to production is a config swap, not a code rewrite: same endpoints shape, different base host and different credentials. Keep the host in config.
# .env.sandbox
DIGILOCKER_BASE_URL=https://api.digitallocker.gov.in
DIGILOCKER_CLIENT_ID=sandbox_client_id
DIGILOCKER_CLIENT_SECRET=sandbox_secret
DIGILOCKER_REDIRECT_URI=https://app.example.in/auth/digilocker/callbackNamoID is built to hold these provider credentials encrypted at rest with AES-256-GCM, so your client secret and any DigiLocker tokens are never sitting in plaintext in a row someone can SELECT. That is the same pattern we apply to every connected provider.
The OAuth consent redirect
The DigiLocker integration is a textbook OAuth 2.0 authorization-code flow. There are three legs: send the user to DigiLocker to consent, receive a one-time code on your callback, and exchange that code for tokens on your backend. DigiLocker layers OpenID Connect on top, so the token response can also tell you basic verified identity about the user.
Step 1: redirect the user to the authorize endpoint. Build the authorization URL with your client ID, a registered redirect URI, the code response type, and a state value you generate and store. The state is your CSRF defence: you check it matches on the way back.
https://api.digitallocker.gov.in/public/oauth2/1/authorize
?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https://app.example.in/auth/digilocker/callback
&state=Xy7s9...randomAlways generate state as unguessable random bytes, store it in the user's session, and reject the callback if it does not match. If DigiLocker supports PKCE for your client type, send a code_challenge too. PKCE binds the authorization code to the client that started the flow, so an intercepted code is useless to anyone else. We are fans of PKCE everywhere, and you can read why in PKCE explained.
Step 2: handle the callback. After the user signs in and consents, DigiLocker redirects to your callback with ?code=...&state=.... Validate state, then exchange the code.
Step 3: exchange the code for tokens on your backend. Call the token endpoint with grant_type=authorization_code, the code, your redirect URI, and your client credentials. Credentials go either as form parameters or as HTTP Basic auth, with the client ID as username and secret as password.
curl -X POST https://api.digitallocker.gov.in/public/oauth2/1/token \
-d "grant_type=authorization_code" \
-d "code=THE_ONE_TIME_CODE" \
-d "redirect_uri=https://app.example.in/auth/digilocker/callback" \
-d "client_id=$DIGILOCKER_CLIENT_ID" \
-d "client_secret=$DIGILOCKER_CLIENT_SECRET"A successful response returns an access token, an expiry, and typically a refresh token, alongside verified profile fields the user consented to share such as name and date of birth. Store the access token server-side only. Never send it to the browser.
{
"access_token": "eyJ...",
"expires_in": 3600,
"token_type": "Bearer",
"refresh_token": "def...",
"id_token": "eyJ...",
"name": "ASHA DEVI",
"dob": "01-01-1990"
}This is where a lot of teams accumulate hidden work: storing tokens safely, refreshing them, logging consent for audit, and repeating all of it for every other rail (WhatsApp OTP, Truecaller, social login). NamoID is built so DigiLocker sits behind the same OIDC issuer URL as the rest, and the consent event is recorded for you. See one issuer URL for auth, India rails, and DPDP for the bigger picture.
Fetching the issued-documents list
With an access token in hand, the first useful call is the Get List of Issued Documents API. This returns the documents that issuers have pushed into the user's locker: the ones that are signed at source and therefore trustworthy. Each entry carries metadata you will need for the next step, including a document URI, the document type (doctype), the issuer, and a description.
Call it as a bearer-authenticated request:
curl https://api.digitallocker.gov.in/public/oauth2/1/files/issued \
-H "Authorization: Bearer eyJ..."A response looks roughly like this:
{
"items": [
{
"name": "Driving Licence",
"type": "file",
"size": "23456",
"date": "10-02-2024",
"mime": ["application/pdf", "application/xml"],
"uri": "in.gov.transport-DRVLC-DL01XXXXXXXX",
"doctype": "DRVLC",
"issuerid": "in.gov.transport",
"issuer": "Ministry of Road Transport and Highways"
}
]
}The two fields that matter most downstream are uri and doctype. The uri is the stable handle you pass to the file API to pull the actual document. The doctype lets you filter for exactly what you need. If you only need a driving licence, do not pull the user's entire locker. Read the doctype, pick the one record you came for, and stop. That is both good privacy hygiene and good DPDP practice: collect only what you need for the stated purpose.
If you are deciding between DigiLocker issued documents, Aadhaar offline XML, and other rails for a given check, the trade-offs are laid out in Aadhaar vs DigiLocker vs offline KYC.
Pulling and verifying a document
Now fetch the document itself. The file API takes a URI from the issued-documents list and returns the document, either as a PDF or, more usefully for automated DigiLocker eKYC, as machine-readable signed XML. The XML form is what you want when you need to parse fields and verify a signature rather than just show a human a PDF.
curl -X POST https://api.digitallocker.gov.in/public/oauth2/1/xml/eaadhaar \
-H "Authorization: Bearer eyJ..." \
-d "uri=in.gov.transport-DRVLC-DL01XXXXXXXX"The response is XML signed by the issuer. Note that XML is not available for every document type, so always handle the case where only a PDF exists.
Verification is the part you must not skip. A fetched document is only trustworthy if you verify its signature. The flow is:
- Receive the signed XML.
- Verify the XML digital signature against the issuer's certificate chain (standard XMLDSig verification).
- Only after the signature checks out, read the field values.
- Record the verification result, not the raw document, wherever you can.
Skip the signature check and trust the parsed fields anyway, and you've built a system that believes whatever bytes came back over the wire. Treat an unsigned or signature-failing document as a hard failure, not a warning.
Here is the privacy decision that separates a good integration from a liability. You usually do not need to store the document. You need to store the result of checking it. For an identity rail, store the verification outcome, a minimal reference, and a consent record. Discard the raw document once you have what you came for.
This is exactly the posture NamoID takes with Aadhaar offline XML: the full XML is processed in memory and never persisted, and we keep only the last four digits, a name-hash, and the signature-verification result. The same minimisation mindset applies to DigiLocker. If you want the deep version of that pattern, see Aadhaar offline e-KYC XML verification.
| Rail | Best for | What you keep |
|---|---|---|
| DigiLocker issued document | Verifying a specific government document (licence, PAN, marksheet) | Verification result, minimal reference, consent record |
| Aadhaar offline XML | Name/DOB/address verification from a user-supplied ZIP | Last-4, name-hash, signature result |
| WhatsApp or SMS OTP | Proving control of a phone number | Verification timestamp, channel |
Common pitfalls, rate limits, and privacy
A few traps catch most teams on their first DigiLocker API integration.
Redirect URI mismatches. The single most common failure. The redirect_uri in your authorize request and your token request must exactly match a URI registered in the portal. Same scheme, host, path, and trailing slash.
Skipping state validation. If you do not validate state on the callback, you have an open door for CSRF on your auth flow. Generate it, store it in the session, compare it, and reject mismatches.
Treating the access token as long-lived. Access tokens expire. Use the refresh token to get a new one rather than dragging the user back through consent every hour. Store refresh tokens encrypted and rotate them. NamoID rotates refresh tokens by default, and reuse of an old refresh token revokes the whole chain, which is a safeguard worth building in wherever you persist OAuth tokens.
Assuming XML always exists. Some documents only return a PDF. Handle the no-XML case instead of crashing.
Rate limits. API Setu enforces rate limits on partner APIs, and they vary by partner and environment. Do not loop the issued-documents API on a tight schedule, do not retry aggressively on a 429, and back off exponentially when you get one. Cache the issued-documents list for the duration of a user's session rather than re-fetching on every page.
Privacy and DPDP. DigiLocker data is personal data about an identifiable person, so the Digital Personal Data Protection Act, 2023 applies. In practice that means: take consent for a specific, stated purpose; collect the minimum (one doctype, not the whole locker); keep an audit trail of when consent was given and what you accessed; and have a deletion path. DigiLocker's own consent screen handles the user-facing grant, but your obligations as the entity processing the result do not end there.
This is where an append-only audit trail earns its keep. NamoID is built so every state change, including a provider connect and a consent grant, appends an immutable event, which gives you a DPDP-grade audit trail without extra plumbing. The same event store backs a DSAR export of a user's full history. If audit trails are on your plate, DPDP audit trail requirements for engineers is the practical companion to this guide, and the broader checklist lives in the DPDP compliance checklist for SaaS.
This section is general information, not legal advice. Confirm your specific obligations with counsel.
FAQ
Is DigiLocker integration free to use?
DigiLocker access through API Setu is provided as a government service, and partner onboarding for Requester APIs goes through the official API Setu partners portal. There is no commercial SDK to buy for the core flow. Your real cost is the onboarding and approval process and the engineering to store tokens, verify signatures, and log consent safely. Check the current official terms, as policy can change.
What is the difference between DigiLocker OAuth and a normal social login?
The protocol is the same OAuth 2.0 authorization-code flow you would use for Google or GitHub. The difference is what you get back. A social login returns profile claims. DigiLocker returns access to government-issued, issuer-signed documents you can verify cryptographically. That makes DigiLocker eKYC suitable for identity verification, not just authentication.
Do I have to store the documents I fetch from DigiLocker?
Usually no, and usually you should not. For most checks you only need the result of verifying a document, plus a consent record, not the raw file. Verify the signature, extract only the fields you need, record the outcome, and discard the document. That is both cleaner engineering and better data-minimisation practice under the DPDP Act.
Can I use DigiLocker alongside Aadhaar and other India verification rails?
Yes, and most products end up needing more than one. DigiLocker covers issued documents, Aadhaar offline XML covers name and address verification from a user-supplied file, and OTP rails prove phone ownership. NamoID is built to put all of these behind one OIDC issuer URL so you integrate once. See the verification-rail decision guide to pick the right one per check.
Talk to us
We are building NamoID so India verification rails like DigiLocker sit behind one OIDC issuer, with consent logged, tokens encrypted, and a DPDP-grade audit trail you get for free. If you are planning a DigiLocker integration and want a second set of eyes, book a 30-minute demo at calendly.com/polymindslabs/30min or reach us at hello@namoid.in. No sign-up needed yet, we are happy to just talk through your flow.