---
title: Signing Sessions
description: Create, use, confirm, list, and revoke temporary wallet-owned
  signing sessions from the browser wallet SDK.
source_url:
  html: https://thru.org/docs/wallet/signing-sessions/
  md: https://thru.org/docs/wallet/signing-sessions.md
---

# Signing Sessions

Use signing sessions when a connected app needs a temporary wallet-owned signer for repeated actions. A session can sign the same `ThruTransactionIntent` shape as `wallet.signTransaction(...)`, but the session handle signs through the wallet’s session key instead of opening the normal approval UI for every action.

## When To Use A Signing Session

Use a signing session when:

- the user has already approved a narrow app flow
- the app needs to submit repeated transactions for the same wallet account
- the app can keep the session short-lived and revocable

Do not use a signing session as a replacement for the initial wallet connection or for actions that should always show the full wallet approval modal.

## Create A Session

`createSigningSession(...)` opens the wallet, asks the user to approve the session, stores the session descriptor in app-local SDK storage, and returns a `ThruSigningSession` handle.

```ts
const session = await wallet.createSigningSession({
  walletAddress,
  durationSeconds: 60 * 30,
  review: {
    appName: "My Thru App",
    instruction: "Repeated transfer approval",
  },
});

console.log(session.id);
console.log(session.walletAddress);
console.log(session.publicKey);
console.log(session.expiresAt);
```

The wallet stores the private key. The SDK stores only the descriptor needed by this app to find and use the session later.

## Sign With A Session

Use the returned session handle to sign a wallet-managed transaction intent. The returned string is the signed raw transaction encoded as base64, ready for submission.

```ts
function bytesToBase64(bytes: Uint8Array): string {
  let binary = "";
  for (let i = 0; i < bytes.length; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  return btoa(binary);
}

function base64ToBytes(value: string): Uint8Array {
  const binary = atob(value);
  const bytes = new Uint8Array(binary.length);
  for (let i = 0; i < binary.length; i++) {
    bytes[i] = binary.charCodeAt(i);
  }
  return bytes;
}

const signedBase64 = await session.signTransaction({
  programAddress,
  instructionData: bytesToBase64(instructionData),
  readWriteAddresses,
  readOnlyAddresses,
  review: {
    appName: "My Thru App",
    programAddress,
    instruction: "Transfer",
  },
});

const signature = await thru.transactions.send(base64ToBytes(signedBase64));
```

Session-backed signing still uses wallet-managed transaction construction. The app supplies the program instruction intent, and the wallet/session path owns the final transaction wire layout.

## List And Reuse Sessions

Signing sessions are app-scoped. Use `getSigningSessions()` to find sessions known to the current SDK storage scope, or `getSigningSession(id)` when you already stored an id in app state.

```ts
const sessions = await wallet.getSigningSessions();
const activeSession = sessions.find(
  (session) =>
    session.walletAddress === walletAddress &&
    session.expiresAt > Math.floor(Date.now() / 1000),
);

if (activeSession) {
  const signedBase64 = await activeSession.signTransaction({
    programAddress,
    instructionData: bytesToBase64(instructionData),
    readWriteAddresses,
    readOnlyAddresses,
  });
}
```

If no session is available, fall back to `wallet.signTransaction(intent)` or ask the user to create a new session.

## Create A Session Instruction

Use `createSigningSessionInstruction(...)` when the app needs to prepare the session authority instruction first, include it in a later user-approved transaction, and confirm the session only after that transaction lands.

```ts
const prepared = await wallet.createSigningSessionInstruction({
  walletAddress,
  walletAccountIdx: 2,
  durationSeconds: 60 * 30,
});

console.log(prepared.session.id);
console.log(prepared.programAddress);
console.log(prepared.instructionData);
```

Include `prepared.instructionData` in the transaction that adds the session authority. After that transaction is accepted on-chain, confirm the session:

```ts
const session = await wallet.confirmSigningSession(prepared.session.id);
```

`confirmSigningSession(id)` asks the wallet to verify the session and then stores the descriptor in the SDK’s app-local storage.

## Revoke A Session

Revoke a session when the user disconnects, when the app no longer needs the temporary signer, or when the app detects that the session is expired.

```ts
await session.revoke();

// Or revoke by id.
await wallet.revokeSigningSession(session.id);
```

Revocation removes the local SDK descriptor and asks the wallet to delete its session key.

## API Shape

```ts
type ThruTransactionIntent = {
  walletAddress?: string;
  programAddress: string;
  instructionData: string;
  readWriteAddresses?: string[];
  readOnlyAddresses?: string[];
  review?: ThruTransactionReviewPayload;
};

type ThruTransactionReviewPayload = {
  appName?: string;
  programAddress?: string;
  abiName?: string;
  instruction?: string;
  simulation?: {
    before?: string;
    after?: string;
  };
  abiReflection?: {
    label?: string;
    kind?: string | null;
    typeName?: string;
    value?: unknown;
    rawHex?: string;
    source?: string;
    error?: string;
  };
};

type ThruSigningSessionDescriptor = {
  id: string;
  walletAddress: string;
  publicKey: string;
  authIdx: number;
  expiresAt: number;
  createdAt: number;
};

type ThruSigningSession = ThruSigningSessionDescriptor & {
  signTransaction(transaction: ThruTransactionIntent): Promise<string>;
  revoke(): Promise<void>;
  toJSON(): ThruSigningSessionDescriptor;
};
```

## Related References

- [Embedded Wallet Integration](https://thru.org/docs/wallet/embedded-wallet-integration.md)
- [Approval and Signing](https://thru.org/docs/wallet/approval-and-signing.md)
- [`@thru/wallet`](https://thru.org/docs/sdks/web-packages/wallet.md)
