import jwt from 'jsonwebtoken'; export interface UserSession { did: string; handle: string; iss: string; aud: string; exp: number; iat: number; } /** * Mints a new JWT for our application's session management. * This token is what SurrealDB will validate. * * @param did - The user's canonical ATproto DID (e.g., "did:plc:...") * @param handle - The user's Bluesky handle (e.g., "user.bsky.social") * @returns A signed JWT string. */ export function mintSurrealJwt(did: string, handle: string): string { const secret = process.env.SURREALDB_JWT_SECRET; if (!secret) { throw new Error('SURREALDB_JWT_SECRET is not set in environment.'); } // This payload is critical. The `did` claim will be used // in SurrealDB's PERMISSIONS clauses. const payload = { // Standard JWT claims iss: 'Ponderants', aud: 'SurrealDB', // Custom claims did: did, handle: handle, }; // Token expires in 7 days const token = jwt.sign(payload, secret, { algorithm: 'HS512', expiresIn: '7d', }); return token; } /** * Verifies and decodes a JWT token. * * @param token - The JWT token to verify * @returns The decoded user session, or null if invalid */ export function verifySurrealJwt(token: string): UserSession | null { const secret = process.env.SURREALDB_JWT_SECRET; if (!secret) { throw new Error('SURREALDB_JWT_SECRET is not set in environment.'); } try { const decoded = jwt.verify(token, secret, { algorithms: ['HS512'], }) as UserSession; return decoded; } catch (error) { console.error('JWT verification failed:', error); return null; } }