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
Section titled “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
Section titled “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.
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
Section titled “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.
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
Section titled “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.
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
Section titled “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.
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:
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
Section titled “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.
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
Section titled “API Shape”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;};