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

  1. Your backend calls POST /verify/v1/init (secret key) and returns the verify_url to the app. See the Integration Guide.
  2. The app opens verify_url — Android in a Chrome Custom Tab, iOS in an ASWebAuthenticationSession.
  3. Xident redirects to your callback_url with ?status&token&user_id when verification finishes.
  4. The app receives that redirect (see "Routing the callback" below), reads the xtk_ token, and sends it to your backend.
  5. 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_url host so the OS opens your app directly on that HTTPS URL. Recommended.
  • Backend bounce — point callback_url at a small page on your server that immediately redirects to your app's custom scheme (e.g. yourapp://verified?status=…&token=…), which ASWebAuthenticationSession / 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 status alone; the authoritative outcome comes from GET /verify/v1/result/{token} (data.status === "completed").

Next Steps