> ## Documentation Index
> Fetch the complete documentation index at: https://docs.polygon.technology/llms.txt
> Use this file to discover all available pages before exploring further.

# Kotlin SDK authentication

> Authenticate with an OIDC ID token, email OTP, or OIDC redirect and activate a wallet.

Authentication establishes an OMS credential. Wallet selection then activates a wallet for that credential and completes the session. Protected wallet operations require both steps.

Starting any authentication flow replaces the current wallet session and pending authentication state.

## Sign in with OIDC ID token

Prefer OIDC ID-token authentication when a native provider SDK supplies an ID token. Your app owns provider sign-in and token acquisition. The OMS Wallet SDK receives the resulting token but does not invoke Android Credential Manager or another provider SDK for you.

Pass the provider result directly to OMS Wallet:

```kotlin theme={null}
import technology.polygon.omswallet.wallet.CompleteAuthResult

val result = omsWallet.wallet.signInWithOidcIdToken(
    idToken = googleIdToken,
    issuer = "https://accounts.google.com",
    audience = "YOUR_WEB_CLIENT_ID",
)
check(result is CompleteAuthResult.WalletSelected)

println("Wallet address: ${result.wallet.address}")
```

`idToken` must be a compact JWT whose payload contains a numeric `exp` claim. Pass the provider ID token, not an OAuth access token or authorization code. `issuer` and `audience` must match the provider configuration used to obtain it. For a custom issuer, you can also set `provider` and `providerLabel`; these values become session metadata.

The maintained Kotlin SDK demo shows Google Sign-In obtaining `googleIdToken` with Android Credential Manager. Generate provider nonces with a cryptographically secure random source and handle provider errors in the application integration.

## Authenticate with email OTP

Email authentication has an in-memory pending step. It is not restored after process death.

```kotlin theme={null}
omsWallet.wallet.startEmailAuth(
    email = "user@example.com",
)

// Complete this after the user enters the emailed code.
val result = omsWallet.wallet.completeEmailAuth(
    code = "123456",
)
check(result is CompleteAuthResult.WalletSelected)
```

`startEmailAuth` stores the requested session lifetime with that pending attempt. A new auth flow or `signOut()` clears it.

## Authenticate through an OIDC redirect

Use redirect authentication when you cannot obtain a provider ID token directly. Unlike email and manual selection state, the Android-backed client persists pending redirect state so the browser round trip can survive activity or process recreation.

For the fixed Google or Apple OMS relay configuration, start the flow with an app callback URI:

```kotlin theme={null}
import technology.polygon.omswallet.wallet.OmsRelayOidcProviders

val started = omsWallet.wallet.startOidcRedirectAuth(
    provider = OmsRelayOidcProviders.google,
    omsRelayReturnUri = "yourapp://auth/callback",
)

println("Open in Custom Tabs: ${started.authorizationUrl}")
```

Register the callback URI for your Android app. The Google and Apple relay values have fixed SDK-owned client IDs, scopes, authorization parameters, and PKCE behavior.

For a provider configuration owned by your app, use `CustomOidcProviderConfig`. Its `providerRedirectUri` is both the OAuth redirect URI and expected callback URI.

```kotlin theme={null}
import technology.polygon.omswallet.wallet.CustomOidcProviderConfig

val started = omsWallet.wallet.startOidcRedirectAuth(
    provider = CustomOidcProviderConfig(
        issuer = "https://issuer.example.com",
        clientId = "YOUR_OIDC_CLIENT_ID",
        authorizationUrl = "https://issuer.example.com/oauth2/authorize",
        providerRedirectUri = "yourapp://auth/callback",
        provider = "corporate",
        providerLabel = "Corporate SSO",
        scopes = listOf("openid", "email", "profile"),
    ),
)
```

## Handle the redirect callback

Pass incoming callback URLs from both `onCreate` and `onNewIntent` to the handler:

```kotlin theme={null}
import technology.polygon.omswallet.wallet.CompleteAuthResult
import technology.polygon.omswallet.wallet.OidcRedirectAuthResult

when (
    val callback = omsWallet.wallet.handleOidcRedirectCallback(
        callbackUrl = intent.data?.toString(),
    )
) {
    is OidcRedirectAuthResult.Completed -> {
        val auth = callback.result
        check(auth is CompleteAuthResult.WalletSelected)
        println(auth.wallet.address)
    }
    OidcRedirectAuthResult.NotOidcRedirectCallback -> Unit
    OidcRedirectAuthResult.NoPendingAuth -> println("Start a new sign-in")
}
```

The handler checks the callback URI and encoded state before consuming pending state. A null, unrelated, or state-mismatched URL returns `NotOidcRedirectCallback` and leaves the pending redirect available. An OIDC-shaped callback with no stored attempt returns `NoPendingAuth`. A matching callback is consumed once: success returns `Completed`, while provider or completion failures throw an `OMSWalletException` and clear that attempt.

Pass `walletSelection` or `sessionLifetimeSeconds` when starting the redirect to persist those choices for completion. A non-null callback argument overrides its stored value.

## Set the session lifetime

Completed auth requests use one week by default: `WalletClient.DEFAULT_SESSION_LIFETIME_SECONDS`, or `604_800` seconds. You can request from 1 second through `WalletClient.MAX_SESSION_LIFETIME_SECONDS`, or `2_592_000` seconds.

For email, set `sessionLifetimeSeconds` on `startEmailAuth`. For ID-token auth, set it on `signInWithOidcIdToken`. For redirects, set it when starting the flow or override it when handling the callback.

## Select a wallet manually

OIDC ID-token, email, and redirect authentication use `WalletSelectionBehavior.Automatic` by default. Automatic mode loads wallets matching the requested type, selects the first match, or creates a wallet when no match exists.

Use manual mode only when your app presents the wallet choices:

```kotlin theme={null}
import technology.polygon.omswallet.wallet.CompleteAuthResult
import technology.polygon.omswallet.wallet.WalletSelectionBehavior

val result = omsWallet.wallet.completeEmailAuth(
    code = "123456",
    walletSelection = WalletSelectionBehavior.Manual,
)
check(result is CompleteAuthResult.WalletSelection)

val pending = result.pendingSelection
val existing = pending.wallets.firstOrNull()
val selected = if (existing == null) {
    pending.createAndSelectWallet(reference = "main")
} else {
    pending.selectWallet(existing.id)
}

println("Selected wallet: ${selected.wallet.address}")
```

`CompleteAuthResult.WalletSelection` means identity authentication succeeded, but no wallet is active. Complete that same pending attempt with `selectWallet` or `createAndSelectWallet`. The pending value becomes stale after selection, a newer auth flow, sign-out, or credential expiry. Redirect authentication returns the same result when it starts with manual selection.

Continue with [Sessions and access](/wallets/sdk/kotlin/sessions-and-access) to restore completed sessions, switch wallets, issue backend ID tokens, and manage request-signing credentials.
