On this page · 12 sections
- Why India moved past SMS OTP in 2026
- What a passkey actually is
- Passkeys vs SMS OTP vs authenticator TOTP
- The two ceremonies: registration and authentication
- Adding passkeys to an iOS app
- Adding passkeys to an Android app
- The server side: your relying party
- Do you still need SMS OTP in India?
- Rollout mistakes we see
- FAQ
- How eCorpIT can help
- References
Summary. Visa Payment Passkey went live in India on 2 July 2026 with IDFC FIRST Bank as the first issuing bank, and it is already usable at Myntra, Paytm, MakeMyTrip and Reliance Digital through fintech partners like Razorpay, PayU and Juspay. It sits on the RBI's authentication directions, issued on 25 September 2025 with a compliance date of 1 April 2026, which make two-factor authentication mandatory for digital payments but stay technology-neutral. The measured case for passkeys is strong: the FIDO Alliance Passkey Index reports a 93% login success rate against 63% for other methods, and Microsoft has reported 98% versus 32% for passkey against password sign-ins. A transactional SMS OTP in India costs ₹0.10 to ₹0.18 per message, and every send needs a DLT-registered template. This guide shows how to add WebAuthn passkeys to an iOS 16 app and an Android 9 app, what the relying-party server must do, and the one question most Indian teams get wrong: whether they can drop SMS OTP. Short answer, not yet.
Why India moved past SMS OTP in 2026
Three things changed at once. The Reserve Bank of India published its authentication directions on 25 September 2025 and gave regulated entities until 1 April 2026 to comply. The rules require at least two authentication factors drawn from separate categories (something you know, something you have, something you are), with at least one factor dynamically generated for card-not-present transactions. From 1 October 2026 the same logic extends to cross-border card-not-present payments. The directions are outcome-based. They do not name a winning technology, and they do not ban SMS OTP.
That last point is where a lot of the 2026 commentary is wrong. Several write-ups claim India "eliminated" SMS OTP in April. It did not. OTP remains a permitted factor. What the RBI did was end the assumption that a single static-plus-OTP flow is enough, and it explicitly opened the door to stronger factors, passkeys among them.
Visa walked through that door on 2 July 2026. Visa Payment Passkey (VPP) is built on FIDO's standards and lets a cardholder authenticate a payment with the phone's native unlock: fingerprint, face, PIN, password or pattern. Visa launched with IDFC FIRST Bank and a partner list that already covers a large slice of Indian checkout: merchants Myntra, Paytm, MakeMyTrip, Tata Starbucks, Reliance Digital and EatSure, plus fintech backbones Juspay, Wibmo, Razorpay, PayU, Pine Labs, BillDesk, M2P Fintech and Paytm Payments Services.
Suresh Sethi, Group Country Manager, India and South Asia at Visa, framed the launch this way: "With Visa Payment Passkey, we are helping make digital commerce safer, more inclusive and easier to use by enabling people to authenticate card payments through familiar device-based experiences such as biometrics, PINs, passwords or patterns."
There is a cost argument underneath the security one. A transactional SMS in India, the category that carries OTPs, runs ₹0.10 to ₹0.18 per delivered message on DLT-registered routes, and TRAI requires every business to register as a principal entity and pre-register each template, with fines of ₹50,000 per instance for non-DLT sends. At scale that is a real line item, and it buys you the least reliable and most phishable factor you own. A passkey costs nothing per authentication once it is set up.
What a passkey actually is
A passkey is a FIDO2 credential: a public and private key pair created on the user's device. The private key is generated inside the device's secure hardware (the Secure Enclave on Apple devices, the hardware-backed keystore on Android) and never leaves it. Your server only ever stores the public key. There is no shared secret to steal, phish, or leak in a database breach, which is the structural reason a passkey beats both passwords and OTPs.
Two properties matter for engineers. First, passkeys are origin-bound. The credential is tied to your relying-party identifier (your domain), so a lookalike phishing site cannot trigger it. Second, modern passkeys are discoverable (resident) credentials synced through iCloud Keychain on Apple and Google Password Manager on Android, so a user who sets up a passkey on their phone can use it on their laptop without re-enrolling.
WebAuthn is the browser and platform API that drives this, and FIDO2 is the umbrella standard (WebAuthn plus the CTAP protocol for external authenticators). On native mobile you do not call WebAuthn directly. On iOS you use the AuthenticationServices framework; on Android you use the Credential Manager API. Both speak the same WebAuthn JSON to your server, which is what keeps a single backend serving web, iOS and Android.
Passkeys vs SMS OTP vs authenticator TOTP
| Dimension | SMS OTP | Authenticator TOTP | Passkey (FIDO2) |
|---|---|---|---|
| Phishing resistance | None (code can be relayed) | Low (code can be relayed) | High (origin-bound, no code to relay) |
| Shared secret on your server | Yes (via SMS provider) | Yes (TOTP seed) | No (only a public key) |
| SIM-swap / interception risk | High | None | None |
| Per-use cost in India | ₹0.10–₹0.18 per SMS | Zero after setup | Zero after setup |
| Login success rate | Baseline | Baseline | 93% vs 63% for other methods (FIDO Index) |
| Works offline | No (needs network for SMS) | Yes | Yes |
| RBI 2FA factor category | Something you have (weak) | Something you have | Have + are, in one gesture |
The success-rate column is the one that changes product decisions. The FIDO Alliance launched its Passkey Index on 13 October 2025 using deployment data from Amazon, Google, Microsoft, PayPal, Target and TikTok, and put passkey login success at 93% against 63% for other methods. Microsoft's own 2024 rollout data showed a 98% success rate for passkeys versus 32% for passwords, with passkey users signing in roughly eight times faster. Higher success rate is higher payment success rate, which is why Visa expects VPP to lift PSR over OTP flows.
The two ceremonies: registration and authentication
Every passkey system has exactly two flows, and both are a short conversation between your server and the device.
Registration (create a passkey). Your server generates a random challenge and a set of creation options (relying-party ID, user handle, allowed algorithms) and sends them as a WebAuthn PublicKeyCredentialCreationOptions JSON. The device creates a key pair, signs the challenge, and returns an attestation object with the new public key. Your server verifies the signature and stores the public key against that user.
Authentication (sign in with a passkey). Your server sends a fresh challenge as PublicKeyCredentialRequestOptions. The device asks the user for biometrics or the screen lock, signs the challenge with the private key, and returns an assertion. Your server verifies it against the stored public key.
A minimal set of creation options from the server looks like this:
{
"challenge": "b64url-random-32-bytes",
"rp": { "id": "ecorpit.com", "name": "eCorpIT" },
"user": {
"id": "b64url-user-handle",
"name": "manu@example.com",
"displayName": "Manu S"
},
"pubKeyCredParams": [
{ "type": "public-key", "alg": -7 },
{ "type": "public-key", "alg": -257 }
],
"authenticatorSelection": {
"residentKey": "required",
"userVerification": "required"
},
"timeout": 60000
}
The challenge must be single-use and verified server-side. residentKey: required asks for a discoverable credential so the user gets one-tap sign-in later. alg -7 is ES256 and -257 is RS256; support both and the platform picks what it can produce.
Adding passkeys to an iOS app
Passkeys work on iOS 16 and later. Three pieces have to line up: the Associated Domains entitlement, the apple-app-site-association (AASA) file on your domain, and the AuthenticationServices calls.
First, add the Associated Domains capability in Xcode with a webcredentials entry:
webcredentials:ecorpit.com
Then host an AASA file at https://ecorpit.com/.well-known/apple-app-site-association (served as application/json, no redirects) that lists your app:
{
"webcredentials": {
"apps": ["ABCDE12345.com.ecorpit.wallet"]
}
}
ABCDE12345 is your Team ID and com.ecorpit.wallet is the bundle identifier. The relying-party identifier you pass in Swift must match the webcredentials: domain exactly, or the sheet silently fails.
Registration in Swift uses ASAuthorizationPlatformPublicKeyCredentialProvider:
import AuthenticationServices
func registerPasskey(challenge: Data, userID: Data, name: String) {
let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(
relyingPartyIdentifier: "ecorpit.com")
let request = provider.createCredentialRegistrationRequest(
challenge: challenge,
name: name,
userID: userID)
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
controller.presentationContextProvider = self
controller.performRequests()
}
Sign-in swaps the registration request for an assertion request built from a server challenge:
func signInWithPasskey(challenge: Data) {
let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(
relyingPartyIdentifier: "ecorpit.com")
let request = provider.createCredentialAssertionRequest(challenge: challenge)
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
controller.performRequests()
}
In the delegate you read the credential's rawAuthenticatorData, signature and clientDataJSON, and post them to your verification endpoint. The private key stays in the Secure Enclave and syncs through iCloud Keychain, so you never handle it.
Adding passkeys to an Android app
On Android, passkeys run through the Credential Manager API (the androidx.credentials Jetpack library) on Android 9 (API 28) and above with current Google Play services. The domain link uses a Digital Asset Links file instead of AASA.
Host assetlinks.json at https://ecorpit.com/.well-known/assetlinks.json:
[
{
"relation": ["delegate_permission/common.get_login_creds"],
"target": {
"namespace": "android_app",
"package_name": "com.ecorpit.wallet",
"sha256_cert_fingerprints": ["AB:CD:EF:..."]
}
}
]
The get_login_creds relation is what lets passkeys and passwords flow between your website and your app. Use the SHA-256 fingerprint of the signing certificate you ship with, including the Play App Signing key.
Registration passes the server's creation-options JSON straight through as CreatePublicKeyCredentialRequest:
val request = CreatePublicKeyCredentialRequest(requestJson = creationOptionsJson)
try {
val result = credentialManager.createCredential(
context = activity,
request = request)
val response = result as CreatePublicKeyCredentialResponse
sendToServer(response.registrationResponseJson)
} catch (e: CreateCredentialException) {
handle(e)
}
Sign-in builds a GetCredentialRequest from a GetPublicKeyCredentialOption:
val option = GetPublicKeyCredentialOption(requestJson = requestOptionsJson)
val request = GetCredentialRequest(listOf(option))
val result = credentialManager.getCredential(context = activity, request = request)
val cred = result.credential as PublicKeyCredential
sendToServer(cred.authenticationResponseJson)
The requestJson in both cases is the exact WebAuthn JSON your server already produces for the web and iOS. That is the payoff of building on WebAuthn: one relying-party server, three clients.
The server side: your relying party
The clients are thin. The security lives on the server, and there are four jobs it must do.
Generate and bind the challenge. Every ceremony starts with a fresh, random, single-use challenge tied to the user session. Store it server-side with a short expiry and reject any assertion whose challenge you did not issue.
Verify the origin and RP ID. On assertion, confirm the clientDataJSON origin matches your app or site and that the RP ID hash matches your domain. This is what makes the credential phishing-resistant, so it cannot be skipped.
Check the signature counter. FIDO authenticators can return a signature counter. If a stored counter goes backward, treat it as a possible cloned credential and step the user up.
Store only public keys. Persist the credential ID, public key, sign counter and user handle. There is no secret to protect here, which is the entire point.
Use a maintained WebAuthn library rather than hand-rolling COSE key parsing and CBOR decoding. webauthn variants exist for Node, Java, Go, Python and .NET, and they handle the attestation formats you do not want to implement yourself.
Do you still need SMS OTP in India?
This is the question that decides your 2026 roadmap, and the honest answer for an Indian consumer app is: keep SMS OTP as a fallback, and lead with passkeys. Here is the decision logic.
| Situation | Lead factor | Keep SMS OTP? |
|---|---|---|
| New fintech or wallet app, 2026 launch | Passkey (biometric) | Yes, as fallback for un-enrolled devices |
| Existing app with millions of OTP users | Passkey opt-in, OTP default | Yes, migrate gradually |
| Feature phone or shared-device user base | Device-bound OTP or PIN | Yes, primary for that segment |
| High-value or cross-border CNP flow | Passkey + dynamic factor | Yes, as one of two factors |
| Internal or employee app | Passkey mandatory | Optional |
Two India-specific realities keep OTP in the picture. Device coverage is the first: passkeys need Android 9 or iOS 16 and a screen lock, and a meaningful share of Indian users are on older or shared handsets where a synced passkey is not available. The second is enrolment. A passkey has to be created before it can be used, so the very first login, or a login on a brand-new device, still needs a bootstrap factor, and SMS OTP is the one almost every Indian user already understands.
The RBI framework does not force the choice. Because it is technology-neutral and outcome-based, an app that offers a passkey (something you are, plus something you have, in one gesture) with an OTP fallback satisfies the two-factor mandate and improves on it. The migration that works is opt-in first: prompt existing users to add a passkey after a successful OTP login, default new users to passkey with OTP as the recovery path, and measure enrolment before you consider making it mandatory. Under the DPDP Act, passkeys also shrink your data surface, because you are no longer routing phone-number-linked codes through a third-party SMS provider for every login. For teams already mapping these obligations, our DPDP Act engineering playbook and the RBI authentication directions guide for cross-border CNP cover the compliance edges in detail.
Rollout mistakes we see
The failures are rarely in the crypto. They are in the plumbing. The AASA or assetlinks file is served with a redirect or the wrong content type, and the passkey sheet fails silently with no error the user can read. The RP ID does not match the associated-domain entry, so registration works in test and breaks in production under a different domain. Teams skip the signature-counter check and lose their one signal for a cloned credential. And the most common one: shipping passkeys with no recovery path, so a user who loses their only device is locked out. The real cost is usually the recovery design, not the registration code. Build the fallback before you build the happy path. For payment-grade flows, the same rigour that goes into RBI digital lending directions belongs in your authentication design.
FAQ
How eCorpIT can help
eCorpIT builds authentication and payment flows for Indian fintech, wallet and commerce apps, including passkey enrolment, WebAuthn relying-party servers and OTP-fallback migration paths that satisfy the RBI's two-factor mandate. Our senior engineering teams are CMMI Level 5 and ISO 27001:2022 certified, and we design applications aligned with DPDP and RBI requirements. If you are planning a passkey rollout or a move off SMS OTP, talk to our engineering team about a build that fits your user base. For the product side of payments, see our fintech payments app development service.
References
- Visa Launches Payment Passkey in India, Reducing Friction in Digital Payments — Visa India newsroom, 2 July 2026.
- Framework on Alternative Authentication Mechanisms for Digital Payment Transactions — Reserve Bank of India, 25 September 2025.
- FIDO Alliance launches Passkey Index, revealing significant passkey uptake and business benefits — FIDO Alliance, 13 October 2025.
- ASAuthorizationPlatformPublicKeyCredentialProvider — Apple Developer Documentation.
- Create a passkey with Credential Manager — Android Developers.
- Credential Manager prerequisites and Digital Asset Links — Android Developers.
- Passkeys (FIDO2) authentication method in Microsoft Entra ID — Microsoft Learn.
- A2P SMS pricing in India 2026: DLT local route vs international route — Message Central.
- Visa passkeys go live in India as IDFC First Bank becomes first issuer — Business Standard, 3 July 2026.
_Last updated: 31 July 2026._