Skip to main content
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, its requested lifetime has not run out, and it 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

activeWallet is a Wallet with id, type, address, reference, and keyOrigin, the same shape as listWallets() entries. Branch on type before passing the address to family-specific code. session is an OMSWalletSession and is non-null exactly when activeWallet is. auth is OMSWalletEmailSessionAuth or OMSWalletOidcSessionAuth; OIDC metadata also records the Redirect or IdToken flow and issuer. expiresAt is the current expiry as an ISO-8601 timestamp, and the SDK keeps it up to date, so read it when you need it instead of caching it. Pending email OTP and manual wallet-selection attempts are not persisted. Pending redirect state is stored separately and must be completed through handleOidcRedirectCallback. session reports only completed wallet sessions, so do not use a null session to infer which pending flow, if any, is active.

One session per project

Every OMSWallet created for the same project and environment shares one session, whether your app creates it once or per Activity. A rotated publishable key for the same project keeps the session.

Keep your UI in sync

A session stays active while it is used. It ends after about 10 days without use, at the lifetime requested at sign-in (180 days by default), or when its credential is revoked. When the session ends, protected operations throw OMSWalletSessionException with code = OMSWalletErrorCode.SessionExpired. If OMS cannot be reached, the session is kept and the operation throws the request error. onSessionChange calls your listener on the Android main thread after every change of activeWallet or session. Subscribe first, then read the current state, so no change is missed:
Listeners are shared by every OMSWallet created for the same project and environment in the process, so they stay registered after the OMSWallet that added them is gone. Unsubscribe when the owner goes away; a listener that captures an Activity otherwise keeps it in memory for the life of the process. After a restart, a new listener first receives the last Expired change until the user signs in again or signs out.

List, switch, and create wallets

List every wallet available to the authenticated credential:
Activate a different existing wallet by its OMS wallet ID:
Or create and activate a wallet:
Both activation methods update the persisted completed session. reference is optional app-defined wallet metadata. Pass walletType = WalletType.Solana or walletType = WalletType.Tron to create a Solana or Tron wallet:

Claim a preallocated wallet

A completed sign-in result lists, in CompleteAuthResult.WalletSelected.claimableWallets, the wallets your project preallocated for the user’s email that sign-in did not claim. See Authentication for how wallets become claimable. Claim one with claimWallet:
claimWallet makes the claimed wallet active, like useWallet. During a pending manual selection, use pendingSelection.claimAndSelectWallet instead.

Import and activate a wallet

Ethereum and Tron imports (WalletImportPrivateKey.Ethereum or EthereumBytes, and WalletImportPrivateKey.Tron or TronBytes) take a private key as bytes or a hex string. Solana imports take a 32-byte seed or 64-byte keypair, as bytes or base58. The SDK never stores the plaintext key. keyOrigin tells you whether a wallet was created by OMS (WalletKeyOrigin.Enclave) or imported (WalletKeyOrigin.Imported). Attestation failures throw an OMSWalletException with code OMSWalletErrorCode.AttestationVerificationFailed. Importing a key whose address is already imported throws OMSWalletRequestException with code OMSWalletErrorCode.WalletAddressAlreadyImported and status 409; select the existing wallet instead.
Development uses Nitro debug-mode attestation. Use only disposable test keys in Development. Staging and Production verify against SDK-pinned enclave measurements.

Keep the three credential concepts separate

The SDK uses three related values for different trust boundaries: 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

Send this token to your backend and verify it there as described in 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 direct or remote grants for the selected wallet:
Each grant contains a WalletCredential with credentialId, ISO-8601 expiresAt, and isCaller. A remote grant also contains its session ID, display metadata, and bounded smart-session grants. For page-at-a-time UI, use listAccessPage(pageSize, cursor, type). For a stream of pages, collect listAccessPages(pageSize, type). Revoke only a grant whose credential has isCaller == false:
For a remote grant, sessionId is required and revokes exactly that session. Revocation changes 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.

Authorize remote access

Remote access grants are bounded EVM smart sessions, so authorizing them requires an active Ethereum wallet. Inspect the remote credential and show its returned metadata to the wallet owner before requesting approval: This example uses Polygon Amoy. Grant limits are raw EVM base-unit amounts. A native-transfer limit is cumulative, so 1000000000000000 wei authorizes up to 0.001 POL across the session.
WaaS caps the requested session expiry at the remote credential’s expiry. A wallet can have up to 100 active remote sessions by default. At the limit, authorizeRemoteAccess fails with OMSWalletRequestException (upstreamError?.code "7208"); revoke a session the wallet no longer needs, then try again. Backend credential registration and remote execution are outside the Kotlin SDK; implement them with the TypeScript SDK’s backend smart sessions guide.

Sign out

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.