> ## 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.

# Swift sessions and access

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

An active session combines a selected wallet with an unexpired OMS credential. The SDK persists completed session metadata and restores it when you create `OMSWallet` again.

## Read restored session state

```swift theme={null}
let omsWallet = try OMSWallet(publishableKey: "YOUR_PUBLISHABLE_KEY")
let session = omsWallet.wallet.session

if let walletAddress = session.walletAddress {
    print("Restored wallet:", walletAddress)
    print("Expires:", session.expiresAt as Any)
    print("Identity:", session.auth?.email as Any)
}
```

`OMSWalletSessionState` contains completed-session metadata: `walletAddress`, `expiresAt`, and authentication metadata in `auth`. For OIDC, the metadata identifies `.idToken` or `.redirect`, the issuer, optional provider details, and an email when OMS returns one.

The request-signing credential is separate. Its non-extractable P-256 private key remains Keychain-managed and is not serialized into `OMSWalletSessionState`. Restoration succeeds only when the completed metadata is unexpired and its Keychain credential can be restored.

<Note>
  A manual `PendingWalletSelection` is not completed session metadata. It remains in memory only until your app activates a wallet.
</Note>

## Observe expiration

Expired sessions are not activated. Keep the returned observation alive while you need notifications. The callback runs on `MainActor`.

```swift theme={null}
let expiryObservation = omsWallet.wallet.addSessionExpiredObserver { event in
    print("Expired wallet:", event.session.walletAddress ?? "unknown")
    print("Expired at:", event.expiredAt)
}

// Cancel when the owner no longer needs notifications.
expiryObservation.cancel()
```

The event retains the expired session snapshot so you can choose the appropriate reauthentication UI.

## List, switch, and create wallets

These operations require the authenticated credential. `listWallets()` follows all server cursors and returns the complete list.

```swift theme={null}
let wallets = try await omsWallet.wallet.listWallets()

if let secondary = wallets.dropFirst().first {
    let selected = try await omsWallet.wallet.useWallet(
        walletId: secondary.id
    )
    print("Selected:", selected.walletAddress)
}
```

Create and activate another wallet for the same credential when your product requires one.

```swift theme={null}
let created = try await omsWallet.wallet.createWallet(
    reference: "trading"
)

print("Created:", created.wallet.address)
```

Both `useWallet` and `createWallet` replace the active wallet while preserving the current session expiry and authentication metadata.

## Understand access objects

Keep these three objects distinct:

| Object            | Purpose                                                                                               |
| ----------------- | ----------------------------------------------------------------------------------------------------- |
| Wallet session    | Local active-wallet state used by protected SDK operations.                                           |
| Wallet ID token   | Short-lived token returned by OMS for your backend to verify the active wallet.                       |
| Access credential | A `CredentialInfo` grant that can make signed requests for the wallet until it expires or is revoked. |

The OIDC provider ID token used during authentication is a fourth object: it is app-owned identity proof consumed as auth input, not an OMS wallet token.

## Request a wallet ID token

Call `getIdToken()` only after a wallet is active. Send the returned string to a backend that verifies it using the OMS issuer and JWKS flow described in [backend wallet verification](/wallets/sdk/guides/backend-wallet-verification).

```swift theme={null}
let walletIdToken = try await omsWallet.wallet.getIdToken(
    ttlSeconds: 3_600,
    customClaims: [
        "role": .string("member")
    ]
)
```

Custom claims originate in the client. Your backend should not treat them as trusted authorization state unless it controls how they are assigned.

## List and revoke access credentials

Use `listAccess()` to load all credential pages for account-management UI.

```swift theme={null}
let credentials = try await omsWallet.wallet.listAccess()

for credential in credentials {
    print(credential.credentialId)
    print(credential.expiresAt)
    print("Current caller:", credential.isCaller)
}
```

Use the async sequence when your UI should process one server page at a time.

```swift theme={null}
for try await page in omsWallet.wallet.listAccessPages(pageSize: 25) {
    for credential in page.credentials {
        print(credential.credentialId, credential.isCaller)
    }
}
```

You can also request one page with `listAccessPage(pageSize:cursor:)`. Revoke only a credential whose `isCaller` value is `false`:

```swift theme={null}
if let credential = credentials.first(where: { !$0.isCaller }) {
    try await omsWallet.wallet.revokeAccess(
        targetCredentialId: credential.credentialId
    )
}
```

Revocation cannot be undone. Revoking the caller invalidates the credential making the current request and prevents subsequent protected operations from that session. Keep caller revocation out of the normal access-management UI.

## Sign out

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

Signing out clears the completed session, Keychain credential, pending redirect state, and pending wallet selection for this SDK scope. It does not revoke other access credentials on the wallet.
