> ## 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 sessions and access

> Restore completed sessions, switch wallets, issue backend ID tokens, and manage wallet access.

A completed session combines an authenticated credential with one selected wallet. The Android-backed `OMSWallet` constructor restores that session automatically when its metadata is valid, unexpired, and still matches the Android Keystore credential.

Protected methods on `omsWallet.wallet` require this active session. Read-only calls on `omsWallet.indexer` do not.

## Read the completed session

```kotlin theme={null}
val session = omsWallet.wallet.session

println("Wallet: ${session.walletAddress}")
println("Expires at: ${session.expiresAt}")
println("Authenticated email: ${session.auth?.email}")
```

`walletAddress` is non-null only after wallet activation. `expiresAt` is the ISO-8601 value returned by OMS. `auth` is `OMSWalletEmailSessionAuth` or `OMSWalletOidcSessionAuth`; OIDC metadata also records the `Redirect` or `IdToken` flow and issuer.

Pending email OTP and manual wallet-selection attempts are not persisted. Pending redirect state is stored separately and must be completed through `handleOidcRedirectCallback`. Do not use `session.walletAddress == null` to infer which pending flow, if any, is active.

## Handle expiration

An expired session becomes inactive before protected wallet work proceeds. The operation throws `OMSWalletSessionException` with `code = OMSWalletErrorCode.SessionExpired`.

Subscribe when the UI should react as the session expires:

```kotlin theme={null}
val unsubscribe = omsWallet.wallet.onSessionExpired { event ->
    println("Reauthenticate ${event.session.auth?.email.orEmpty()}")
}

// Call when the lifecycle owner no longer needs the callback.
unsubscribe()
```

Listeners run on the Android main thread. A new listener receives the latest expiration event until a new auth flow, a new completed session, or `signOut()` clears it. The event contains the expired snapshot, not a still-active session.

## List, switch, and create wallets

List every wallet available to the authenticated credential:

```kotlin theme={null}
val wallets = omsWallet.wallet.listWallets()

wallets.forEach { wallet ->
    println("${wallet.id}: ${wallet.address}")
}
```

Activate a different existing wallet by its OMS wallet ID:

```kotlin theme={null}
val selected = omsWallet.wallet.useWallet(walletId = wallets.last().id)
println("Active wallet: ${selected.walletAddress}")
```

Or create and activate a wallet:

```kotlin theme={null}
val created = omsWallet.wallet.createWallet(reference = "savings")
println("Created wallet: ${created.wallet.address}")
```

Both activation methods update the persisted completed session. `reference` is optional app-defined wallet metadata.

## Keep the three credential concepts separate

The SDK uses three related values for different trust boundaries:

| Value                             | Purpose                                                                                                      |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| Completed wallet session          | Local SDK state containing the selected wallet, expiry, and auth metadata                                    |
| OMS Wallet ID token               | A token from `getIdToken()` that your app sends to its backend as proof for the active wallet                |
| Request-signing access credential | An SDK-managed P-256 credential that authorizes wallet API requests and appears in access-management results |

The provider ID token passed to `signInWithOidcIdToken` is a fourth value used only to authenticate the user's external identity. It is not the token returned by `getIdToken()`.

## Issue an ID token for your backend

```kotlin theme={null}
val idToken = omsWallet.wallet.getIdToken(
    ttlSeconds = 300u,
)
```

Send this token to your backend and verify it there as described in [Backend wallet verification](/wallets/sdk/guides/backend-wallet-verification). `customClaims` accepts `Map<String, JsonElement>` when you need app-provided context. Treat app-provided claims as untrusted unless your backend controls their values.

## Inspect request-signing access

`listAccess` follows all cursors and returns the credentials that can access the selected wallet:

```kotlin theme={null}
val credentials = omsWallet.wallet.listAccess(pageSize = 25u)

credentials.forEach { credential ->
    println("${credential.credentialId} caller=${credential.isCaller}")
}
```

Each `CredentialInfo` includes `credentialId`, ISO-8601 `expiresAt`, and `isCaller`. For page-at-a-time UI, use `listAccessPage(pageSize, cursor)`. For a stream of pages, collect `listAccessPages(pageSize)`.

Revoke only a credential whose `isCaller` value is `false`:

```kotlin theme={null}
credentials.firstOrNull { !it.isCaller }?.let { credential ->
    omsWallet.wallet.revokeAccess(
        targetCredentialId = credential.credentialId,
    )
}
```

Revocation changes that credential's server-side wallet access. Revoking the caller invalidates the credential making the current request and prevents subsequent protected operations from that session. It does not switch the selected wallet.

## Sign out

```kotlin theme={null}
omsWallet.wallet.signOut()
```

`signOut()` synchronously clears in-memory state and attempts to remove completed-session metadata, pending redirect state, and the local request-signing credential. If persistent cleanup fails, it throws `OMSWalletStorageException` after the in-memory session has already been cleared.
