Secure storage and distribution of cryptographic keys in ATProto applications
at main 53 lines 1.5 kB view raw
1import { error, IRequest } from 'itty-router' 2import { ServiceJwtVerifier, VerifiedJwt } from '@atcute/xrpc-server/auth' 3import { 4 CompositeDidDocumentResolver, 5 PlcDidDocumentResolver, 6 WebDidDocumentResolver, 7} from '@atcute/identity-resolver' 8import { Nsid, Did } from '@atcute/lexicons' 9 10const didDocResolver = new CompositeDidDocumentResolver({ 11 methods: { 12 plc: new PlcDidDocumentResolver(), 13 web: new WebDidDocumentResolver(), 14 }, 15}) 16const createJwtVerifier = (did: Did<'web'>) => 17 new ServiceJwtVerifier({ 18 resolver: didDocResolver, 19 serviceDid: did, 20 }) 21 22export default async function authMiddleware( 23 serviceDid: Did<'web'>, 24 ctx: IRequest, 25) { 26 const url = new URL(ctx.url) 27 if (!url.pathname.startsWith('/xrpc/')) { 28 return error(404) 29 } 30 const lxm = url.pathname.split('/xrpc/')[1] as Nsid 31 32 const authorization = ctx.headers.get('authorization') 33 if (!authorization) { 34 return error(403, 'Authorization token required.') 35 } 36 if (!authorization.startsWith('Bearer ')) { 37 return error(403, 'Bearer token required') 38 } 39 40 const jwt = authorization.split('Bearer ')[1] 41 const jwtVerifier = createJwtVerifier(serviceDid) 42 const jwtPayload = await jwtVerifier.verify(jwt, { lxm }) 43 if (!jwtPayload.ok) { 44 console.error('Error validating JWT:', jwtPayload.error) 45 return error(403, 'Could not verify authorization JWT.') 46 } 47 48 ctx.audience = jwtPayload.value.audience 49 ctx.lxm = jwtPayload.value.lxm 50 ctx.did = jwtPayload.value.issuer 51 52 return undefined 53}