La documentación se publica en inglés.

DocumentationSign in

Mobile SDKs

Native helpers for Android, iOS, Flutter and React Native. The system browser, PKCE, verified HTTPS callbacks, and no client secret in the app.

The packages

The mobile SDK repository holds five packages. Every adapter uses the hosted authorization experience, the authorization code flow with PKCE S256, state validation, and the operating system's browser authentication surface.

PackageRuntimeBrowser surface
packages/android-kotlinAndroid / KotlinAndroid Custom Tabs
packages/ios-swiftiOS / SwiftASWebAuthenticationSession
packages/flutterFlutter on Android and iOSflutter_appauth
packages/react-nativeReact Nativereact-native-app-auth
packages/coreNode reference and contract testsOAuth helper primitives

Four rules the SDKs enforce

The system browser, always
ASWebAuthenticationSession on iOS, Custom Tabs on Android. Never an embedded WebView: a WebView lets the host application observe everything typed into it, the person cannot tell your screen from an imitation, and passkeys will not work.
A public client
A mobile application never carries a client secret — a secret inside a binary is a published secret. The app authenticates at the token endpoint with PKCE alone (none), or exchanges the code from your backend.
Verified HTTPS callbacks
Universal Links on iOS, App Links on Android, registered exactly in the developer console. A custom URL scheme can be claimed by any application on the device, and UnifyID refuses untrusted custom schemes.
One transaction, stored encrypted
State, nonce and the PKCE verifier survive the app being backgrounded and nothing else: Keychain or Android Keystore, bound to the transaction, with a short expiry. A returning callback that finds no transaction fails closed.

The flow in each SDK

Android / Kotlin
val client = UnifyIDClient(
  UnifyIDConfig(
    clientId = "<your client id>",
    redirectUri = "https://app.example/oauth/callback",
    scopes = listOf("openid", "identity_verified"),
  )
)

val transaction = client.createTransaction()
client.authorize(activity, transaction)
// in onNewIntent:
val code = client.complete(callbackIntent, transaction)
iOS / Swift
let configuration = UnifyIDConfiguration(
  clientId: "<your client id>",
  redirectURI: URL(string: "https://app.example/oauth/callback")!,
  scopes: ["openid", "identity_verified"]
)

let client = UnifyIDClient(configuration: configuration)
let result = try await client.authorize(anchor: anchor)

The SDK generates PKCE, opens the system session and validates the callback. Then exchange the code with the original verifier — from the app as a public client, or from your backend.

apple-app-site-association
{ "applinks": { "details": [
  { "appIDs": ["TEAMID.com.example.app"],
    "components": [{ "/": "/oauth/callback" }] }
]}}

Before you ship

  • Test cancellation, a restart mid-flow, an offline return, an expired transaction and an unverified callback, and confirm none of them produces a session.
  • Confirm the production callback domain is verified in the shipped build. A verification file that works in staging and not in production is a launch-day failure.
  • Do not log authorization codes, access tokens or identity claims. Send crash diagnostics without personal identity information.
  • Handle revoked consent explicitly: the next userinfo call answers 401, and the app needs somewhere to send the person.

What this does not do

  • The SDKs do not change the sign-in. It is the same authorize, consent, code, token, userinfo as the web; the SDK opens the browser and catches the callback.
  • The drop-in component is not for mobile. <unifyid-continue> deliberately uses a full redirect on narrow screens; a native app uses these SDKs instead.

Verified against API commit 234dba22 on 2026-10-18. The routes, scopes, checklist, events and limits on these pages are read from that export, not typed.