import { error, IRequest } from 'itty-router' import { ServiceJwtVerifier, VerifiedJwt } from '@atcute/xrpc-server/auth' import { CompositeDidDocumentResolver, PlcDidDocumentResolver, WebDidDocumentResolver, } from '@atcute/identity-resolver' import { Nsid, Did } from '@atcute/lexicons' const didDocResolver = new CompositeDidDocumentResolver({ methods: { plc: new PlcDidDocumentResolver(), web: new WebDidDocumentResolver(), }, }) const createJwtVerifier = (did: Did<'web'>) => new ServiceJwtVerifier({ resolver: didDocResolver, serviceDid: did, }) export default async function authMiddleware( serviceDid: Did<'web'>, ctx: IRequest, ) { const url = new URL(ctx.url) if (!url.pathname.startsWith('/xrpc/')) { return error(404) } const lxm = url.pathname.split('/xrpc/')[1] as Nsid const authorization = ctx.headers.get('authorization') if (!authorization) { return error(403, 'Authorization token required.') } if (!authorization.startsWith('Bearer ')) { return error(403, 'Bearer token required') } const jwt = authorization.split('Bearer ')[1] const jwtVerifier = createJwtVerifier(serviceDid) const jwtPayload = await jwtVerifier.verify(jwt, { lxm }) if (!jwtPayload.ok) { console.error('Error validating JWT:', jwtPayload.error) return error(403, 'Could not verify authorization JWT.') } ctx.audience = jwtPayload.value.audience ctx.lxm = jwtPayload.value.lxm ctx.did = jwtPayload.value.issuer return undefined }