/** * OAuth State Store for @atproto/oauth-client-node * * Stores temporary OAuth state during the authorization flow. * Used for CSRF protection and PKCE verification. */ import Surreal from 'surrealdb'; import type { NodeSavedStateStore, NodeSavedState } from '@atproto/oauth-client-node'; /** * Get a SurrealDB connection with root credentials. * Used for OAuth state management. */ async function getDB(): Promise { const db = new Surreal(); await db.connect(process.env.SURREALDB_URL!); await db.signin({ username: process.env.SURREALDB_USER!, password: process.env.SURREALDB_PASS!, }); await db.use({ namespace: process.env.SURREALDB_NS!, database: process.env.SURREALDB_DB!, }); return db; } /** * Create an OAuth state store backed by SurrealDB. * * The state store is used during the OAuth flow to store * temporary data (PKCE verifier, DPoP key, etc.) that is * retrieved when the user returns from the authorization server. * * States expire after 1 hour (enforced by database event). */ export function createStateStore(): NodeSavedStateStore { return { async set(key: string, value: NodeSavedState): Promise { const db = await getDB(); try { await db.query( 'CREATE oauth_state SET key = $key, value = $value', { key, value } ); } finally { await db.close(); } }, async get(key: string): Promise { const db = await getDB(); try { const [result] = await db.query<[{ value: NodeSavedState }[]]>( 'SELECT value FROM oauth_state WHERE key = $key', { key } ); return result?.[0]?.value; } finally { await db.close(); } }, async del(key: string): Promise { const db = await getDB(); try { await db.query( 'DELETE oauth_state WHERE key = $key', { key } ); } finally { await db.close(); } }, }; }