Mobile apps
Native apps use the same backend-first flow as the web. Your backend creates the session and reads the result with your secret key; the app's only job is to open the verification URL and catch the callback. There is no on-device SDK to install and no secret key ever ships in the app.
Never put your secret key (sk_live_…) in a mobile app. Anyone can extract it from a shipped binary. POST /verify/v1/init and GET /verify/v1/result/{token} must run on your server.
The flow
- Your backend calls
POST /verify/v1/init(secret key) and returns theverify_urlto the app. See the Integration Guide. - The app opens
verify_url— Android in a Chrome Custom Tab, iOS in anASWebAuthenticationSession. - Xident redirects to your
callback_urlwith?status&token&user_idwhen verification finishes. - The app receives that redirect (see "Routing the callback" below), reads the
xtk_token, and sends it to your backend. - Your backend calls
GET /verify/v1/result/{token}(secret key) to read the outcome.
Android
// verifyUrl comes from YOUR backend (POST /verify/v1/init with your secret key).
// Open it in a Chrome Custom Tab:
val intent = CustomTabsIntent.Builder().build()
intent.launchUrl(context, Uri.parse(verifyUrl))
// When verification finishes, Xident redirects to your callback_url. Route it back
// into the app with an Android App Link, then read the params in your Activity:
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
intent.data?.let { uri ->
val status = uri.getQueryParameter("status") // success | failed | cancelled
val token = uri.getQueryParameter("token") // xtk_... result token
// Send `token` to your backend, which calls GET /verify/v1/result/{token}.
}
}
iOS
// verifyURL comes from YOUR backend (POST /verify/v1/init with your secret key).
let session = ASWebAuthenticationSession(
url: verifyURL,
callbackURLScheme: "yourapp" // your app's custom scheme
) { callbackURL, error in
guard let callbackURL else { return }
let items = URLComponents(url: callbackURL, resolvingAgainstBaseURL: false)?.queryItems
let status = items?.first { $0.name == "status" }?.value // success | failed | cancelled
let token = items?.first { $0.name == "token" }?.value // xtk_... result token
// Send token to your backend, which calls GET /verify/v1/result/{token}.
}
session.presentationContextProvider = self
session.start()
Routing the callback into your app
Xident requires callback_url to be HTTPS (or http://localhost in development) — custom URL schemes like myapp:// are not accepted at init. To get the HTTPS redirect back into your app, use one of:
- Universal Links (iOS) / App Links (Android) — register your
callback_urlhost so the OS opens your app directly on that HTTPS URL. Recommended. - Backend bounce — point
callback_urlat a small page on your server that immediately redirects to your app's custom scheme (e.g.yourapp://verified?status=…&token=…), whichASWebAuthenticationSession/ the Custom Tab then catches.
Security
- Init and result run on your backend with the secret key — never on the device.
- Don't trust the callback
statusalone; the authoritative outcome comes fromGET /verify/v1/result/{token}(data.status === "completed").
Next Steps
- Quick Start — the backend flow end-to-end
- Integration Guide — init options and callback handling
- API Reference — full generated API documentation