/** * 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 { // Use the key as the record ID for direct lookup // Escape special characters in the key for SurrealDB record ID await db.create(`oauth_state:⟨${key}⟩`, { key, value, created_at: new Date().toISOString(), }); } finally { await db.close(); } }, async get(key: string): Promise { const db = await getDB(); try { // Select directly by record ID const result = await db.select<{ value: NodeSavedState }>(`oauth_state:⟨${key}⟩`); // db.select() returns an array when selecting a specific record ID const record = Array.isArray(result) ? result[0] : result; return record?.value; } finally { await db.close(); } }, async del(key: string): Promise { const db = await getDB(); try { // Delete directly by record ID await db.delete(`oauth_state:⟨${key}⟩`); } finally { await db.close(); } }, }; }