diff --git a/src/server/Handler.ts b/src/server/Handler.ts index 08b5364..d694e0e 100644 --- a/src/server/Handler.ts +++ b/src/server/Handler.ts @@ -620,6 +620,241 @@ export declare namespace feePayer { > } +/** + * Defines an Authorization Relay request handler that serves an HTML page + * for authorizing cross-domain access keys using an existing passkey. + * + * @param options - Options. + * @returns Request handler. + */ +export function authorizationRelay(options: authorizationRelay.Options) { + const { kv } = options + + const rp = (() => { + if (!options.rp) return undefined + return { + id: options.rp.id, + name: options.rp.name ?? options.rp.id, + } + })() + + const router = from(options) + + // Challenge endpoint for WebAuthn signing + router.get('/authorize/challenge', async () => { + const challenge = Hex.random(32) + await kv.set(`challenge:${challenge}`, '1') + + return Response.json({ + challenge, + ...(rp ? { rp } : {}), + }) + }) + + // Serve the authorization HTML page + router.get('/authorize', async ({ request }) => { + const url = new URL(request.url) + const keyAddress = url.searchParams.get('keyAddress') ?? '' + const hash = url.searchParams.get('hash') ?? '' + const chainId = url.searchParams.get('chainId') ?? '' + const expiry = url.searchParams.get('expiry') ?? '' + const origin = url.searchParams.get('origin') ?? '' + const rpId = rp?.id ?? url.hostname + + const html = ` + + + + +Authorize Access Key + + + +
+

Authorize Access Key

+
+
Access Key
+
+
+
+
Expires
+
+
+
+
Requesting Origin
+
+
+
+
Chain ID
+
+
+
+ + +
+
+
+ + +` + + return new Response(html, { + headers: { 'Content-Type': 'text/html; charset=utf-8' }, + }) + }) + + return router +} + +export declare namespace authorizationRelay { + export type Options = from.Options & { + /** The KV store to use for challenge management. */ + kv: Kv.Kv + /** The RP to use for WebAuthn. */ + rp?: { id: string; name?: string } | undefined + /** CORS configuration. */ + cors?: from.Options['cors'] | undefined + } +} + /** @internal */ function normalizeHeaders(headers?: Headers | Record): Headers { if (!headers) return new Headers()