@atproto/lex-server 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @atproto/lex-server
2
2
 
3
+ ## 0.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#4501](https://github.com/bluesky-social/atproto/pull/4501) [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add service auth authentication method
8
+
9
+ - Updated dependencies [[`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98), [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98), [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98), [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98), [`2f78893`](https://github.com/bluesky-social/atproto/commit/2f78893ace3bbf14d4bac36837820ddb46658c98)]:
10
+ - @atproto/lex-data@0.0.6
11
+ - @atproto/did@0.2.4
12
+ - @atproto/lex-schema@0.0.7
13
+ - @atproto/lex-cbor@0.0.6
14
+ - @atproto/lex-json@0.0.6
15
+ - @atproto-labs/did-resolver@0.2.5
16
+
3
17
  ## 0.0.2
4
18
 
5
19
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { LexError, type LexErrorCode, type LexErrorData, } from '@atproto/lex-data';
2
2
  export * from './errors.js';
3
3
  export * from './lex-server.js';
4
+ export * from './service-auth.js';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,mBAAmB,CAAA;AAE1B,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,mBAAmB,CAAA;AAE1B,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,mBAAmB,CAAA"}
package/dist/index.js CHANGED
@@ -6,4 +6,5 @@ var lex_data_1 = require("@atproto/lex-data");
6
6
  Object.defineProperty(exports, "LexError", { enumerable: true, get: function () { return lex_data_1.LexError; } });
7
7
  tslib_1.__exportStar(require("./errors.js"), exports);
8
8
  tslib_1.__exportStar(require("./lex-server.js"), exports);
9
+ tslib_1.__exportStar(require("./service-auth.js"), exports);
9
10
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;AAAA,8CAI0B;AAHxB,oGAAA,QAAQ,OAAA;AAKV,sDAA2B;AAC3B,0DAA+B","sourcesContent":["export {\n LexError,\n type LexErrorCode,\n type LexErrorData,\n} from '@atproto/lex-data'\n\nexport * from './errors.js'\nexport * from './lex-server.js'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;AAAA,8CAI0B;AAHxB,oGAAA,QAAQ,OAAA;AAKV,sDAA2B;AAC3B,0DAA+B;AAC/B,4DAAiC","sourcesContent":["export {\n LexError,\n type LexErrorCode,\n type LexErrorData,\n} from '@atproto/lex-data'\n\nexport * from './errors.js'\nexport * from './lex-server.js'\nexport * from './service-auth.js'\n"]}
@@ -1,6 +1,6 @@
1
1
  import { InferMethodInput, InferMethodMessage, InferMethodOutput, InferMethodOutputBody, InferMethodOutputEncoding, InferMethodParams, Main, Procedure, Query, Subscription } from '@atproto/lex-schema';
2
2
  type Awaitable<T> = T | Promise<T>;
3
- type LexMethod = Query | Procedure | Subscription;
3
+ export type LexMethod = Query | Procedure | Subscription;
4
4
  export type NetAddr = {
5
5
  hostname: string;
6
6
  port: number;
@@ -37,19 +37,20 @@ export type LexRouterHandlerOutput<Method extends Query | Procedure> = Response
37
37
  export type LexRouterMethodHandler<Method extends Query | Procedure = Query | Procedure, Credentials = unknown> = (ctx: LexRouterHandlerContext<Method, Credentials>) => Awaitable<LexRouterHandlerOutput<Method>>;
38
38
  export type LexRouterMethodConfig<Method extends Query | Procedure = Query | Procedure, Credentials = unknown> = {
39
39
  handler: LexRouterMethodHandler<Method, Credentials>;
40
- auth: LexRouterAuth<Method, Credentials>;
40
+ auth: LexRouterAuth<Credentials, Method>;
41
41
  };
42
42
  export type LexRouterSubscriptionHandler<Method extends Subscription = Subscription, Credentials = unknown> = (ctx: LexRouterHandlerContext<Method, Credentials>) => AsyncIterable<InferMethodMessage<Method>>;
43
43
  export type LexRouterSubscriptionConfig<Method extends Subscription = Subscription, Credentials = unknown> = {
44
44
  handler: LexRouterSubscriptionHandler<Method, Credentials>;
45
- auth: LexRouterAuth<Method, Credentials>;
45
+ auth: LexRouterAuth<Credentials, Method>;
46
46
  };
47
47
  export type LexRouterAuthContext<Method extends LexMethod = LexMethod> = {
48
+ method: Method;
48
49
  params: InferMethodParams<Method>;
49
50
  request: Request;
50
51
  connection?: ConnectionInfo;
51
52
  };
52
- export type LexRouterAuth<Method extends LexMethod = LexMethod, Credentials = unknown> = (ctx: LexRouterAuthContext<Method>) => Credentials | Promise<Credentials>;
53
+ export type LexRouterAuth<Credentials = unknown, Method extends LexMethod = LexMethod> = (ctx: LexRouterAuthContext<Method>) => Credentials | Promise<Credentials>;
53
54
  export type LexErrorHandlerContext = {
54
55
  error: unknown;
55
56
  request: Request;
@@ -1 +1 @@
1
- {"version":3,"file":"lex-server.d.ts","sourceRoot":"","sources":["../src/lex-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lex-server.d.ts","sourceRoot":"","sources":["../src/lex-server.ts"],"names":[],"mappings":"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"}
@@ -43,7 +43,7 @@ class LexRouter {
43
43
  const url = new URL(request.url);
44
44
  const params = method.parameters.fromURLSearchParams(url.searchParams);
45
45
  const credentials = auth
46
- ? await auth({ params, request, connection })
46
+ ? await auth({ method, params, request, connection })
47
47
  : undefined;
48
48
  const input = await getInput(request);
49
49
  const output = await methodHandler({
@@ -119,7 +119,7 @@ class LexRouter {
119
119
  const url = new URL(request.url);
120
120
  const params = method.parameters.fromURLSearchParams(url.searchParams);
121
121
  const credentials = auth
122
- ? await auth({ params, request, connection })
122
+ ? await auth({ method, params, request, connection })
123
123
  : undefined;
124
124
  signal.throwIfAborted();
125
125
  const iterable = methodHandler({
@@ -1 +1 @@
1
- {"version":3,"file":"lex-server.js","sourceRoot":"","sources":["../src/lex-server.ts"],"names":[],"mappings":"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","sourcesContent":["import { encode } from '@atproto/lex-cbor'\nimport { LexError, LexValue, isPlainObject, ui8Concat } from '@atproto/lex-data'\nimport { lexParse, lexToJson } from '@atproto/lex-json'\nimport {\n InferMethodInput,\n InferMethodMessage,\n InferMethodOutput,\n InferMethodOutputBody,\n InferMethodOutputEncoding,\n InferMethodParams,\n Main,\n NsidString,\n Procedure,\n Query,\n Subscription,\n getMain,\n isNsidString,\n} from '@atproto/lex-schema'\nimport { drainWebsocket } from './lib/drain-websocket.js'\n\ntype Awaitable<T> = T | Promise<T>\ntype LexMethod = Query | Procedure | Subscription\n\nexport type NetAddr = {\n hostname: string\n port: number\n transport: 'tcp' | 'udp'\n}\n\nexport type UnixAddr = {\n path: string\n transport: 'unix' | 'unixpacket'\n}\n\nexport type Addr = NetAddr | UnixAddr | undefined\n\nexport type ConnectionInfo<A extends Addr = Addr> = {\n remoteAddr: A\n completed: Promise<void>\n}\n\ntype Handler = (\n request: Request,\n connection?: ConnectionInfo,\n) => Promise<Response>\n\nexport type LexRouterHandlerContext<Method extends LexMethod, Credentials> = {\n credentials: Credentials\n input: InferMethodInput<Method, Body>\n params: InferMethodParams<Method>\n request: Request\n signal: AbortSignal\n connection?: ConnectionInfo\n}\n\ntype AsOptionalPayloadOptions<T> = T extends undefined | void\n ? { encoding?: undefined; body?: undefined }\n : T\n\nexport type LexRouterHandlerOutput<Method extends Query | Procedure> =\n | Response\n | ({\n headers?: HeadersInit\n } & (InferMethodOutputEncoding<Method> extends 'application/json'\n ? {\n // Allow omitting body when output is JSON\n encoding?: 'application/json'\n body: InferMethodOutputBody<Method>\n }\n : AsOptionalPayloadOptions<InferMethodOutput<Method, BodyInit>>))\n\nexport type LexRouterMethodHandler<\n Method extends Query | Procedure = Query | Procedure,\n Credentials = unknown,\n> = (\n ctx: LexRouterHandlerContext<Method, Credentials>,\n) => Awaitable<LexRouterHandlerOutput<Method>>\n\nexport type LexRouterMethodConfig<\n Method extends Query | Procedure = Query | Procedure,\n Credentials = unknown,\n> = {\n handler: LexRouterMethodHandler<Method, Credentials>\n auth: LexRouterAuth<Method, Credentials>\n}\n\nexport type LexRouterSubscriptionHandler<\n Method extends Subscription = Subscription,\n Credentials = unknown,\n> = (\n ctx: LexRouterHandlerContext<Method, Credentials>,\n) => AsyncIterable<InferMethodMessage<Method>>\n\nexport type LexRouterSubscriptionConfig<\n Method extends Subscription = Subscription,\n Credentials = unknown,\n> = {\n handler: LexRouterSubscriptionHandler<Method, Credentials>\n auth: LexRouterAuth<Method, Credentials>\n}\n\nexport type LexRouterAuthContext<Method extends LexMethod = LexMethod> = {\n params: InferMethodParams<Method>\n request: Request\n connection?: ConnectionInfo\n}\n\nexport type LexRouterAuth<\n Method extends LexMethod = LexMethod,\n Credentials = unknown,\n> = (ctx: LexRouterAuthContext<Method>) => Credentials | Promise<Credentials>\n\nexport type LexErrorHandlerContext = {\n error: unknown\n request: Request\n method: LexMethod\n}\n\nexport type UpgradeWebSocket = (request: Request) => {\n socket: WebSocket\n response: Response\n}\n\nexport type LexRouterOptions = {\n upgradeWebSocket?: UpgradeWebSocket\n onHandlerError?: (ctx: LexErrorHandlerContext) => void | Promise<void>\n highWaterMark?: number\n lowWaterMark?: number\n}\n\nexport class LexRouter {\n private handlers: Map<NsidString, Handler> = new Map()\n\n constructor(readonly options: LexRouterOptions = {}) {}\n\n add<M extends Subscription>(\n ns: Main<M>,\n handler: LexRouterSubscriptionHandler<M, void>,\n ): this\n add<M extends Subscription, Credentials>(\n ns: Main<M>,\n config: LexRouterSubscriptionConfig<M, Credentials>,\n ): this\n add<M extends Query | Procedure>(\n ns: Main<M>,\n handler: LexRouterMethodHandler<M, void>,\n ): this\n add<M extends Query | Procedure, Credentials>(\n ns: Main<M>,\n config: LexRouterMethodConfig<M, Credentials>,\n ): this\n add<M extends LexMethod>(\n ns: Main<M>,\n config:\n | LexRouterSubscriptionHandler<any, any>\n | LexRouterSubscriptionConfig<any, any>\n | LexRouterMethodHandler<any, any>\n | LexRouterMethodConfig<any, any>,\n ) {\n const method = getMain(ns)\n if (this.handlers.has(method.nsid)) {\n throw new TypeError(`Method ${method.nsid} already registered`)\n }\n const methodConfig =\n typeof config === 'function'\n ? { handler: config, auth: undefined }\n : config\n\n const handler: Handler =\n method.type === 'subscription'\n ? this.buildSubscriptionHandler(\n method,\n methodConfig.handler as LexRouterSubscriptionHandler<any, any>,\n methodConfig.auth,\n )\n : this.buildMethodHandler(\n method,\n methodConfig.handler as LexRouterMethodHandler<any, any>,\n methodConfig.auth,\n )\n\n this.handlers.set(method.nsid, handler)\n\n return this\n }\n\n private buildMethodHandler<Method extends Query | Procedure, Credentials>(\n method: Method,\n methodHandler: LexRouterMethodHandler<Method, Credentials>,\n auth?: LexRouterAuth<Method, Credentials>,\n ): Handler {\n const getInput = (\n method.type === 'procedure'\n ? getProcedureInput.bind(method)\n : getQueryInput.bind(method)\n ) as (request: Request) => Promise<InferMethodInput<Method, Body>>\n\n return async (request, connection) => {\n // @NOTE CORS requests should be handled by a middleware before reaching\n // this point.\n if (\n (method.type === 'procedure' && request.method !== 'POST') ||\n (method.type === 'query' &&\n request.method !== 'GET' &&\n request.method !== 'HEAD')\n ) {\n return Response.json(\n { error: 'InvalidRequest', message: 'Method not allowed' },\n { status: 405 },\n )\n }\n\n try {\n const url = new URL(request.url)\n const params = method.parameters.fromURLSearchParams(url.searchParams)\n\n const credentials = auth\n ? await auth({ params, request, connection })\n : (undefined as Credentials)\n\n const input = await getInput(request)\n\n const output = await methodHandler({\n credentials,\n params,\n input,\n request,\n connection,\n signal: request.signal,\n })\n\n if (output instanceof Response) {\n return output\n }\n\n // @TODO add validation of output based on method.output.schema?\n\n if (output.body === undefined && output.encoding === undefined) {\n return new Response(null, { status: 200, headers: output.headers })\n }\n\n if (method.output?.encoding === 'application/json') {\n return Response.json(lexToJson(output.body as LexValue), {\n status: 200,\n headers: output.headers,\n })\n }\n\n const headers = new Headers(output.headers)\n headers.set('content-type', output.encoding!)\n return new Response(output.body, { status: 200, headers })\n } catch (error) {\n return this.handleError(request, method, error)\n }\n }\n }\n\n private buildSubscriptionHandler<Method extends Subscription, Credentials>(\n method: Method,\n methodHandler: LexRouterSubscriptionHandler<Method, Credentials>,\n auth?: LexRouterAuth<Method, Credentials>,\n ): Handler {\n const {\n onHandlerError,\n upgradeWebSocket = (globalThis as any).Deno?.upgradeWebSocket as\n | UpgradeWebSocket\n | undefined,\n } = this.options\n if (!upgradeWebSocket) {\n throw new TypeError(\n 'WebSocket upgrade not supported in this environment. Please provide an upgradeWebSocket option when creating the LexRouter.',\n )\n }\n\n return async (request, connection) => {\n if (request.method !== 'GET') {\n return Response.json(\n { error: 'InvalidRequest', message: 'Method not allowed' },\n { status: 405 },\n )\n }\n\n if (\n request.headers.get('connection')?.toLowerCase() !== 'upgrade' ||\n request.headers.get('upgrade')?.toLowerCase() !== 'websocket'\n ) {\n return Response.json(\n {\n error: 'InvalidRequest',\n message: 'XRPC subscriptions are only available over WebSocket',\n },\n {\n status: 426,\n headers: {\n Connection: 'Upgrade',\n Upgrade: 'websocket',\n },\n },\n )\n }\n\n if (request.signal.aborted) {\n return Response.json(\n { error: 'RequestAborted', message: 'The request was aborted' },\n { status: 499 },\n )\n }\n\n try {\n const { response, socket } = upgradeWebSocket(request)\n\n // @NOTE We are using a distinct signal than request.signal because that\n // signal may get aborted before the WebSocket is closed (this is the\n // case with Deno).\n const abortController = new AbortController()\n const { signal } = abortController\n const abort = () => abortController.abort()\n\n const onMessage = (event: unknown) => {\n const error = new LexError(\n 'InvalidRequest',\n 'XRPC subscriptions do not accept messages',\n { cause: event },\n )\n socket.send(encodeErrorFrame(error))\n socket.close(1008, error.error)\n }\n\n const onOpen = async () => {\n try {\n const url = new URL(request.url)\n const params = method.parameters.fromURLSearchParams(\n url.searchParams,\n )\n\n const credentials: Credentials = auth\n ? await auth({ params, request, connection })\n : (undefined as Credentials)\n\n signal.throwIfAborted()\n\n const iterable = methodHandler({\n credentials,\n params,\n input: undefined as InferMethodInput<Method, Body>,\n request,\n connection,\n signal,\n })\n\n const iterator = iterable[Symbol.asyncIterator]()\n\n signal.addEventListener('abort', async () => {\n // @NOTE will cause the process to crash if this throws\n await iterator.return?.()\n })\n\n while (!signal.aborted && socket.readyState === 1) {\n const result = await iterator.next()\n if (result.done) break\n\n // @TODO add validation of output based on method.output.schema?\n\n const data = encodeMessageFrame(method, result.value)\n\n socket.send(data)\n\n // Apply backpressure by waiting for the buffered data to drain\n // before generating the next message\n await drainWebsocket(socket, signal, this.options)\n }\n\n if (socket.readyState === 1) {\n socket.close(1000)\n }\n } catch (error) {\n // If the socket is still open, send an error frame before closing\n if (socket.readyState === 1) {\n const lexError =\n error instanceof LexError\n ? error\n : new LexError('InternalError', 'An internal error occurred')\n\n socket.send(encodeErrorFrame(lexError))\n\n socket.close(\n // https://www.rfc-editor.org/rfc/rfc6455#section-7.4.1\n error instanceof LexError ? 1008 : 1011,\n lexError.error,\n )\n }\n\n // Only report unexpected processing errors\n if (onHandlerError && !isAbortReason(request.signal, error)) {\n await onHandlerError({ error, request, method })\n }\n } finally {\n abortController.abort()\n }\n }\n\n socket.addEventListener('error', abort)\n socket.addEventListener('close', abort)\n socket.addEventListener('open', onOpen)\n socket.addEventListener('message', onMessage)\n\n return response\n } catch (error) {\n return this.handleError(request, method, error)\n }\n }\n }\n\n private async handleError(\n request: Request,\n method: LexMethod,\n error: unknown,\n ) {\n // Only report unexpected processing errors\n const { onHandlerError } = this.options\n if (onHandlerError && !isAbortReason(request.signal, error)) {\n await onHandlerError({ error, request, method })\n }\n\n if (error instanceof LexError) {\n return error.toResponse()\n }\n\n return Response.json(\n { error: 'InternalError', message: 'An internal error occurred' },\n { status: 500 },\n )\n }\n\n handle: Handler = async (\n request: Request,\n connection?: ConnectionInfo,\n ): Promise<Response> => {\n const nsid = extractMethodNsid(request)\n\n const handler = (this.handlers as Map<string | null, Handler>).get(nsid)\n if (handler) return handler(request, connection)\n\n if (!nsid || !isNsidString(nsid)) {\n return Response.json(\n {\n error: 'InvalidRequest',\n message: 'Invalid XRPC method path',\n },\n { status: 404 },\n )\n }\n\n return Response.json(\n {\n error: 'MethodNotImplemented',\n message: `XRPC method \"${nsid}\" not implemented on this server`,\n },\n { status: 501 },\n )\n }\n}\n\nfunction extractMethodNsid(request: Request): string | null {\n const { pathname } = new URL(request.url)\n if (!pathname.startsWith('/xrpc/')) return null\n if (pathname.includes('/', 6)) return null\n // We don't really need to validate the NSID here, the existence of the route\n // (which is looked up based on an NSID) is sufficient.\n return pathname.slice(6)\n}\n\nasync function getProcedureInput<M extends Procedure>(\n this: M,\n request: Request,\n): Promise<InferMethodInput<M, Body>> {\n const encodingRaw = request.headers\n .get('content-type')\n ?.split(';')[0]\n .trim()\n .toLowerCase()\n\n const encoding =\n encodingRaw ||\n // If the caller did not provide a content-type, but the method\n // expects an input, assume binary\n (request.body != null && this.input.encoding != null\n ? 'application/octet-stream'\n : undefined)\n\n if (!this.input.matchesEncoding(encoding)) {\n throw new LexError('InvalidRequest', `Invalid content-type: ${encoding}`)\n }\n\n if (this.input.encoding === 'application/json') {\n // @TODO limit size?\n const body = this.input.schema\n ? this.input.schema.parse(lexParse(await request.text()))\n : lexParse(await request.text())\n return { encoding, body } as InferMethodInput<M, Body>\n } else if (this.input.encoding) {\n const body: Body = request\n return { encoding, body } as InferMethodInput<M, Body>\n } else {\n return undefined as InferMethodInput<M, Body>\n }\n}\n\nasync function getQueryInput<M extends Query>(\n this: M,\n request: Request,\n): Promise<InferMethodInput<M, Body>> {\n if (\n request.body ||\n request.headers.has('content-type') ||\n request.headers.has('content-length')\n ) {\n throw new LexError('InvalidRequest', 'GET requests must not have a body')\n }\n\n return undefined as InferMethodInput<M, Body>\n}\n\n// Pre-encoded frame header for error frames\nconst ERROR_FRAME_HEADER = /*#__PURE__*/ encode({ op: -1 })\n\nfunction encodeErrorFrame(error: LexError): Uint8Array {\n return ui8Concat([ERROR_FRAME_HEADER, encode(error.toJSON())])\n}\n\n// Pre-encoded frame header for message frames with unknown type\nconst UNKNOWN_MESSAGE_FRAME_HEADER = /*#__PURE__*/ encode({ op: 1 })\n\nfunction encodeMessageFrame(method: Subscription, value: LexValue): Uint8Array {\n if (isPlainObject(value) && typeof value.$type === 'string') {\n const { $type, ...rest } = value\n return ui8Concat([\n encode({\n op: 1,\n t:\n // If $type starts with `nsid#`, strip the NSID prefix\n $type.charCodeAt(0) !== 0x23 && // '#'\n $type.charCodeAt(method.nsid.length) === 0x23 && // '#'\n $type.startsWith(method.nsid)\n ? $type.slice(method.nsid.length)\n : $type,\n }),\n encode(rest),\n ])\n }\n\n return ui8Concat([UNKNOWN_MESSAGE_FRAME_HEADER, encode(value)])\n}\n\nfunction isAbortReason(signal: AbortSignal, error: unknown): boolean {\n if (!signal.aborted || signal.reason == null) return false\n return (\n error === signal.reason ||\n (error instanceof Error && error.cause === signal.reason)\n )\n}\n"]}
1
+ {"version":3,"file":"lex-server.js","sourceRoot":"","sources":["../src/lex-server.ts"],"names":[],"mappings":"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","sourcesContent":["import { encode } from '@atproto/lex-cbor'\nimport { LexError, LexValue, isPlainObject, ui8Concat } from '@atproto/lex-data'\nimport { lexParse, lexToJson } from '@atproto/lex-json'\nimport {\n InferMethodInput,\n InferMethodMessage,\n InferMethodOutput,\n InferMethodOutputBody,\n InferMethodOutputEncoding,\n InferMethodParams,\n Main,\n NsidString,\n Procedure,\n Query,\n Subscription,\n getMain,\n isNsidString,\n} from '@atproto/lex-schema'\nimport { drainWebsocket } from './lib/drain-websocket.js'\n\ntype Awaitable<T> = T | Promise<T>\nexport type LexMethod = Query | Procedure | Subscription\n\nexport type NetAddr = {\n hostname: string\n port: number\n transport: 'tcp' | 'udp'\n}\n\nexport type UnixAddr = {\n path: string\n transport: 'unix' | 'unixpacket'\n}\n\nexport type Addr = NetAddr | UnixAddr | undefined\n\nexport type ConnectionInfo<A extends Addr = Addr> = {\n remoteAddr: A\n completed: Promise<void>\n}\n\ntype Handler = (\n request: Request,\n connection?: ConnectionInfo,\n) => Promise<Response>\n\nexport type LexRouterHandlerContext<Method extends LexMethod, Credentials> = {\n credentials: Credentials\n input: InferMethodInput<Method, Body>\n params: InferMethodParams<Method>\n request: Request\n signal: AbortSignal\n connection?: ConnectionInfo\n}\n\ntype AsOptionalPayloadOptions<T> = T extends undefined | void\n ? { encoding?: undefined; body?: undefined }\n : T\n\nexport type LexRouterHandlerOutput<Method extends Query | Procedure> =\n | Response\n | ({\n headers?: HeadersInit\n } & (InferMethodOutputEncoding<Method> extends 'application/json'\n ? {\n // Allow omitting body when output is JSON\n encoding?: 'application/json'\n body: InferMethodOutputBody<Method>\n }\n : AsOptionalPayloadOptions<InferMethodOutput<Method, BodyInit>>))\n\nexport type LexRouterMethodHandler<\n Method extends Query | Procedure = Query | Procedure,\n Credentials = unknown,\n> = (\n ctx: LexRouterHandlerContext<Method, Credentials>,\n) => Awaitable<LexRouterHandlerOutput<Method>>\n\nexport type LexRouterMethodConfig<\n Method extends Query | Procedure = Query | Procedure,\n Credentials = unknown,\n> = {\n handler: LexRouterMethodHandler<Method, Credentials>\n auth: LexRouterAuth<Credentials, Method>\n}\n\nexport type LexRouterSubscriptionHandler<\n Method extends Subscription = Subscription,\n Credentials = unknown,\n> = (\n ctx: LexRouterHandlerContext<Method, Credentials>,\n) => AsyncIterable<InferMethodMessage<Method>>\n\nexport type LexRouterSubscriptionConfig<\n Method extends Subscription = Subscription,\n Credentials = unknown,\n> = {\n handler: LexRouterSubscriptionHandler<Method, Credentials>\n auth: LexRouterAuth<Credentials, Method>\n}\n\nexport type LexRouterAuthContext<Method extends LexMethod = LexMethod> = {\n method: Method\n params: InferMethodParams<Method>\n request: Request\n connection?: ConnectionInfo\n}\n\nexport type LexRouterAuth<\n Credentials = unknown,\n Method extends LexMethod = LexMethod,\n> = (ctx: LexRouterAuthContext<Method>) => Credentials | Promise<Credentials>\n\nexport type LexErrorHandlerContext = {\n error: unknown\n request: Request\n method: LexMethod\n}\n\nexport type UpgradeWebSocket = (request: Request) => {\n socket: WebSocket\n response: Response\n}\n\nexport type LexRouterOptions = {\n upgradeWebSocket?: UpgradeWebSocket\n onHandlerError?: (ctx: LexErrorHandlerContext) => void | Promise<void>\n highWaterMark?: number\n lowWaterMark?: number\n}\n\nexport class LexRouter {\n private handlers: Map<NsidString, Handler> = new Map()\n\n constructor(readonly options: LexRouterOptions = {}) {}\n\n add<M extends Subscription>(\n ns: Main<M>,\n handler: LexRouterSubscriptionHandler<M, void>,\n ): this\n add<M extends Subscription, Credentials>(\n ns: Main<M>,\n config: LexRouterSubscriptionConfig<M, Credentials>,\n ): this\n add<M extends Query | Procedure>(\n ns: Main<M>,\n handler: LexRouterMethodHandler<M, void>,\n ): this\n add<M extends Query | Procedure, Credentials>(\n ns: Main<M>,\n config: LexRouterMethodConfig<M, Credentials>,\n ): this\n add<M extends LexMethod>(\n ns: Main<M>,\n config:\n | LexRouterSubscriptionHandler<any, any>\n | LexRouterSubscriptionConfig<any, any>\n | LexRouterMethodHandler<any, any>\n | LexRouterMethodConfig<any, any>,\n ) {\n const method = getMain(ns)\n if (this.handlers.has(method.nsid)) {\n throw new TypeError(`Method ${method.nsid} already registered`)\n }\n const methodConfig =\n typeof config === 'function'\n ? { handler: config, auth: undefined }\n : config\n\n const handler: Handler =\n method.type === 'subscription'\n ? this.buildSubscriptionHandler(\n method,\n methodConfig.handler as LexRouterSubscriptionHandler<any, any>,\n methodConfig.auth,\n )\n : this.buildMethodHandler(\n method,\n methodConfig.handler as LexRouterMethodHandler<any, any>,\n methodConfig.auth,\n )\n\n this.handlers.set(method.nsid, handler)\n\n return this\n }\n\n private buildMethodHandler<Method extends Query | Procedure, Credentials>(\n method: Method,\n methodHandler: LexRouterMethodHandler<Method, Credentials>,\n auth?: LexRouterAuth<Credentials, Method>,\n ): Handler {\n const getInput = (\n method.type === 'procedure'\n ? getProcedureInput.bind(method)\n : getQueryInput.bind(method)\n ) as (request: Request) => Promise<InferMethodInput<Method, Body>>\n\n return async (request, connection) => {\n // @NOTE CORS requests should be handled by a middleware before reaching\n // this point.\n if (\n (method.type === 'procedure' && request.method !== 'POST') ||\n (method.type === 'query' &&\n request.method !== 'GET' &&\n request.method !== 'HEAD')\n ) {\n return Response.json(\n { error: 'InvalidRequest', message: 'Method not allowed' },\n { status: 405 },\n )\n }\n\n try {\n const url = new URL(request.url)\n const params = method.parameters.fromURLSearchParams(url.searchParams)\n\n const credentials = auth\n ? await auth({ method, params, request, connection })\n : (undefined as Credentials)\n\n const input = await getInput(request)\n\n const output = await methodHandler({\n credentials,\n params,\n input,\n request,\n connection,\n signal: request.signal,\n })\n\n if (output instanceof Response) {\n return output\n }\n\n // @TODO add validation of output based on method.output.schema?\n\n if (output.body === undefined && output.encoding === undefined) {\n return new Response(null, { status: 200, headers: output.headers })\n }\n\n if (method.output?.encoding === 'application/json') {\n return Response.json(lexToJson(output.body as LexValue), {\n status: 200,\n headers: output.headers,\n })\n }\n\n const headers = new Headers(output.headers)\n headers.set('content-type', output.encoding!)\n return new Response(output.body, { status: 200, headers })\n } catch (error) {\n return this.handleError(request, method, error)\n }\n }\n }\n\n private buildSubscriptionHandler<Method extends Subscription, Credentials>(\n method: Method,\n methodHandler: LexRouterSubscriptionHandler<Method, Credentials>,\n auth?: LexRouterAuth<Credentials, Method>,\n ): Handler {\n const {\n onHandlerError,\n upgradeWebSocket = (globalThis as any).Deno?.upgradeWebSocket as\n | UpgradeWebSocket\n | undefined,\n } = this.options\n if (!upgradeWebSocket) {\n throw new TypeError(\n 'WebSocket upgrade not supported in this environment. Please provide an upgradeWebSocket option when creating the LexRouter.',\n )\n }\n\n return async (request, connection) => {\n if (request.method !== 'GET') {\n return Response.json(\n { error: 'InvalidRequest', message: 'Method not allowed' },\n { status: 405 },\n )\n }\n\n if (\n request.headers.get('connection')?.toLowerCase() !== 'upgrade' ||\n request.headers.get('upgrade')?.toLowerCase() !== 'websocket'\n ) {\n return Response.json(\n {\n error: 'InvalidRequest',\n message: 'XRPC subscriptions are only available over WebSocket',\n },\n {\n status: 426,\n headers: {\n Connection: 'Upgrade',\n Upgrade: 'websocket',\n },\n },\n )\n }\n\n if (request.signal.aborted) {\n return Response.json(\n { error: 'RequestAborted', message: 'The request was aborted' },\n { status: 499 },\n )\n }\n\n try {\n const { response, socket } = upgradeWebSocket(request)\n\n // @NOTE We are using a distinct signal than request.signal because that\n // signal may get aborted before the WebSocket is closed (this is the\n // case with Deno).\n const abortController = new AbortController()\n const { signal } = abortController\n const abort = () => abortController.abort()\n\n const onMessage = (event: unknown) => {\n const error = new LexError(\n 'InvalidRequest',\n 'XRPC subscriptions do not accept messages',\n { cause: event },\n )\n socket.send(encodeErrorFrame(error))\n socket.close(1008, error.error)\n }\n\n const onOpen = async () => {\n try {\n const url = new URL(request.url)\n const params = method.parameters.fromURLSearchParams(\n url.searchParams,\n )\n\n const credentials: Credentials = auth\n ? await auth({ method, params, request, connection })\n : (undefined as Credentials)\n\n signal.throwIfAborted()\n\n const iterable = methodHandler({\n credentials,\n params,\n input: undefined as InferMethodInput<Method, Body>,\n request,\n connection,\n signal,\n })\n\n const iterator = iterable[Symbol.asyncIterator]()\n\n signal.addEventListener('abort', async () => {\n // @NOTE will cause the process to crash if this throws\n await iterator.return?.()\n })\n\n while (!signal.aborted && socket.readyState === 1) {\n const result = await iterator.next()\n if (result.done) break\n\n // @TODO add validation of output based on method.output.schema?\n\n const data = encodeMessageFrame(method, result.value)\n\n socket.send(data)\n\n // Apply backpressure by waiting for the buffered data to drain\n // before generating the next message\n await drainWebsocket(socket, signal, this.options)\n }\n\n if (socket.readyState === 1) {\n socket.close(1000)\n }\n } catch (error) {\n // If the socket is still open, send an error frame before closing\n if (socket.readyState === 1) {\n const lexError =\n error instanceof LexError\n ? error\n : new LexError('InternalError', 'An internal error occurred')\n\n socket.send(encodeErrorFrame(lexError))\n\n socket.close(\n // https://www.rfc-editor.org/rfc/rfc6455#section-7.4.1\n error instanceof LexError ? 1008 : 1011,\n lexError.error,\n )\n }\n\n // Only report unexpected processing errors\n if (onHandlerError && !isAbortReason(request.signal, error)) {\n await onHandlerError({ error, request, method })\n }\n } finally {\n abortController.abort()\n }\n }\n\n socket.addEventListener('error', abort)\n socket.addEventListener('close', abort)\n socket.addEventListener('open', onOpen)\n socket.addEventListener('message', onMessage)\n\n return response\n } catch (error) {\n return this.handleError(request, method, error)\n }\n }\n }\n\n private async handleError(\n request: Request,\n method: LexMethod,\n error: unknown,\n ) {\n // Only report unexpected processing errors\n const { onHandlerError } = this.options\n if (onHandlerError && !isAbortReason(request.signal, error)) {\n await onHandlerError({ error, request, method })\n }\n\n if (error instanceof LexError) {\n return error.toResponse()\n }\n\n return Response.json(\n { error: 'InternalError', message: 'An internal error occurred' },\n { status: 500 },\n )\n }\n\n handle: Handler = async (\n request: Request,\n connection?: ConnectionInfo,\n ): Promise<Response> => {\n const nsid = extractMethodNsid(request)\n\n const handler = (this.handlers as Map<string | null, Handler>).get(nsid)\n if (handler) return handler(request, connection)\n\n if (!nsid || !isNsidString(nsid)) {\n return Response.json(\n {\n error: 'InvalidRequest',\n message: 'Invalid XRPC method path',\n },\n { status: 404 },\n )\n }\n\n return Response.json(\n {\n error: 'MethodNotImplemented',\n message: `XRPC method \"${nsid}\" not implemented on this server`,\n },\n { status: 501 },\n )\n }\n}\n\nfunction extractMethodNsid(request: Request): string | null {\n const { pathname } = new URL(request.url)\n if (!pathname.startsWith('/xrpc/')) return null\n if (pathname.includes('/', 6)) return null\n // We don't really need to validate the NSID here, the existence of the route\n // (which is looked up based on an NSID) is sufficient.\n return pathname.slice(6)\n}\n\nasync function getProcedureInput<M extends Procedure>(\n this: M,\n request: Request,\n): Promise<InferMethodInput<M, Body>> {\n const encodingRaw = request.headers\n .get('content-type')\n ?.split(';')[0]\n .trim()\n .toLowerCase()\n\n const encoding =\n encodingRaw ||\n // If the caller did not provide a content-type, but the method\n // expects an input, assume binary\n (request.body != null && this.input.encoding != null\n ? 'application/octet-stream'\n : undefined)\n\n if (!this.input.matchesEncoding(encoding)) {\n throw new LexError('InvalidRequest', `Invalid content-type: ${encoding}`)\n }\n\n if (this.input.encoding === 'application/json') {\n // @TODO limit size?\n const body = this.input.schema\n ? this.input.schema.parse(lexParse(await request.text()))\n : lexParse(await request.text())\n return { encoding, body } as InferMethodInput<M, Body>\n } else if (this.input.encoding) {\n const body: Body = request\n return { encoding, body } as InferMethodInput<M, Body>\n } else {\n return undefined as InferMethodInput<M, Body>\n }\n}\n\nasync function getQueryInput<M extends Query>(\n this: M,\n request: Request,\n): Promise<InferMethodInput<M, Body>> {\n if (\n request.body ||\n request.headers.has('content-type') ||\n request.headers.has('content-length')\n ) {\n throw new LexError('InvalidRequest', 'GET requests must not have a body')\n }\n\n return undefined as InferMethodInput<M, Body>\n}\n\n// Pre-encoded frame header for error frames\nconst ERROR_FRAME_HEADER = /*#__PURE__*/ encode({ op: -1 })\n\nfunction encodeErrorFrame(error: LexError): Uint8Array {\n return ui8Concat([ERROR_FRAME_HEADER, encode(error.toJSON())])\n}\n\n// Pre-encoded frame header for message frames with unknown type\nconst UNKNOWN_MESSAGE_FRAME_HEADER = /*#__PURE__*/ encode({ op: 1 })\n\nfunction encodeMessageFrame(method: Subscription, value: LexValue): Uint8Array {\n if (isPlainObject(value) && typeof value.$type === 'string') {\n const { $type, ...rest } = value\n return ui8Concat([\n encode({\n op: 1,\n t:\n // If $type starts with `nsid#`, strip the NSID prefix\n $type.charCodeAt(0) !== 0x23 && // '#'\n $type.charCodeAt(method.nsid.length) === 0x23 && // '#'\n $type.startsWith(method.nsid)\n ? $type.slice(method.nsid.length)\n : $type,\n }),\n encode(rest),\n ])\n }\n\n return ui8Concat([UNKNOWN_MESSAGE_FRAME_HEADER, encode(value)])\n}\n\nfunction isAbortReason(signal: AbortSignal, error: unknown): boolean {\n if (!signal.aborted || signal.reason == null) return false\n return (\n error === signal.reason ||\n (error instanceof Error && error.cause === signal.reason)\n )\n}\n"]}
@@ -0,0 +1,67 @@
1
+ import { AtprotoDid, AtprotoDidDocument } from '@atproto/did';
2
+ import { DidString } from '@atproto/lex-schema';
3
+ import { CreateDidResolverOptions } from '@atproto-labs/did-resolver';
4
+ import { LexRouterAuth } from './lex-server.js';
5
+ /**
6
+ * A function to check and record nonce uniqueness.
7
+ */
8
+ export type UniqueNonceChecker = (nonce: string) => Promise<boolean>;
9
+ export type ServiceAuthOptions = CreateDidResolverOptions & {
10
+ /**
11
+ * Expected audience ("aud") claim in the JWT token. Set to `null` to skip
12
+ * audience verification (not recommended).
13
+ */
14
+ audience: null | DidString;
15
+ /**
16
+ * Function to check and record nonce uniqueness. The value checked here must
17
+ * be unique within {@link ServiceAuthOptions.maxAge} seconds before and after
18
+ * the current time.
19
+ *
20
+ * @param nonce - The nonce to check.
21
+ */
22
+ unique: UniqueNonceChecker;
23
+ /**
24
+ * Maximum age of the JWT token in seconds.
25
+ *
26
+ * @default 300 (5 minutes)
27
+ */
28
+ maxAge?: number;
29
+ };
30
+ export type ServiceAuthCredentials = {
31
+ did: AtprotoDid;
32
+ didDocument: AtprotoDidDocument;
33
+ jwt: ParsedJwt;
34
+ };
35
+ /**
36
+ * Creates an authentication handler for LexRouter that verifies AT protocol
37
+ * "service auth" JWT bearer tokens signed by decentralized identifiers (DIDs).
38
+ */
39
+ export declare function serviceAuth({ audience, maxAge, unique, ...options }: ServiceAuthOptions): LexRouterAuth<ServiceAuthCredentials>;
40
+ export type ParseJwtOptions = {
41
+ maxAge: number;
42
+ audience: null | DidString;
43
+ unique: UniqueNonceChecker;
44
+ lxm: string;
45
+ };
46
+ export type ParsedJwt = {
47
+ header: HeaderObject;
48
+ payload: PayloadObject;
49
+ message: Uint8Array;
50
+ signature: Uint8Array;
51
+ };
52
+ type HeaderObject = {
53
+ alg: string;
54
+ typ?: string;
55
+ };
56
+ type PayloadObject = {
57
+ iss: DidString;
58
+ aud: DidString;
59
+ exp: number;
60
+ iat?: number;
61
+ nbf?: number;
62
+ lxm?: string;
63
+ nonce?: string;
64
+ };
65
+ export declare function isPayloadObject(obj: unknown): obj is PayloadObject;
66
+ export {};
67
+ //# sourceMappingURL=service-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-auth.d.ts","sourceRoot":"","sources":["../src/service-auth.ts"],"names":[],"mappings":"AACA,OAAO,EACL,UAAU,EACV,kBAAkB,EAGnB,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,SAAS,EAAe,MAAM,qBAAqB,CAAA;AAC5D,OAAO,EACL,wBAAwB,EAEzB,MAAM,4BAA4B,CAAA;AAEnC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAI/C;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAEpE,MAAM,MAAM,kBAAkB,GAAG,wBAAwB,GAAG;IAC1D;;;OAGG;IACH,QAAQ,EAAE,IAAI,GAAG,SAAS,CAAA;IAC1B;;;;;;OAMG;IACH,MAAM,EAAE,kBAAkB,CAAA;IAC1B;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,GAAG,EAAE,UAAU,CAAA;IACf,WAAW,EAAE,kBAAkB,CAAA;IAC/B,GAAG,EAAE,SAAS,CAAA;CACf,CAAA;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,MAAe,EACf,MAAM,EACN,GAAG,OAAO,EACX,EAAE,kBAAkB,GAAG,aAAa,CAAC,sBAAsB,CAAC,CAyD5D;AA2ED,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,IAAI,GAAG,SAAS,CAAA;IAC1B,MAAM,EAAE,kBAAkB,CAAA;IAC1B,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,MAAM,EAAE,YAAY,CAAA;IACpB,OAAO,EAAE,aAAa,CAAA;IACtB,OAAO,EAAE,UAAU,CAAA;IACnB,SAAS,EAAE,UAAU,CAAA;CACtB,CAAA;AA4HD,KAAK,YAAY,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AASjD,KAAK,aAAa,GAAG;IACnB,GAAG,EAAE,SAAS,CAAA;IACd,GAAG,EAAE,SAAS,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AACD,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,aAAa,CAalE"}
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serviceAuth = serviceAuth;
4
+ exports.isPayloadObject = isPayloadObject;
5
+ const tslib_1 = require("tslib");
6
+ const crypto = tslib_1.__importStar(require("@atproto/crypto"));
7
+ const did_1 = require("@atproto/did");
8
+ const lex_data_1 = require("@atproto/lex-data");
9
+ const lex_schema_1 = require("@atproto/lex-schema");
10
+ const did_resolver_1 = require("@atproto-labs/did-resolver");
11
+ const errors_js_1 = require("./errors.js");
12
+ const BEARER_PREFIX = 'Bearer ';
13
+ /**
14
+ * Creates an authentication handler for LexRouter that verifies AT protocol
15
+ * "service auth" JWT bearer tokens signed by decentralized identifiers (DIDs).
16
+ */
17
+ function serviceAuth({ audience, maxAge = 5 * 60, unique, ...options }) {
18
+ const didResolver = (0, did_resolver_1.createDidResolver)(options);
19
+ return async ({ request, method }) => {
20
+ const { signal } = request;
21
+ const jwt = await parseJwtBearer(request, {
22
+ lxm: method.nsid,
23
+ maxAge,
24
+ audience,
25
+ unique,
26
+ });
27
+ let didDocument = await didResolver
28
+ .resolve(jwt.payload.iss, { signal })
29
+ .catch((cause) => {
30
+ throw new errors_js_1.LexServerAuthError('AuthenticationRequired', 'Could not resolve DID document', { Bearer: { error: 'DidResolutionFailed' } }, { cause });
31
+ });
32
+ const key = getAtprotoSigningKey(didDocument);
33
+ if (!key || !(await verifyJwt(jwt, key))) {
34
+ signal.throwIfAborted();
35
+ // Try refreshing the DID document in case it was updated
36
+ didDocument = await didResolver
37
+ .resolve(jwt.payload.iss, { signal, noCache: true })
38
+ .catch((cause) => {
39
+ throw new errors_js_1.LexServerAuthError('AuthenticationRequired', 'Could not resolve DID document', { Bearer: { error: 'DidResolutionFailed' } }, { cause });
40
+ });
41
+ // Verify again with the fresh key (if it changed)
42
+ const keyFresh = getAtprotoSigningKey(didDocument);
43
+ if (!keyFresh || key === keyFresh || !(await verifyJwt(jwt, keyFresh))) {
44
+ throw new errors_js_1.LexServerAuthError('AuthenticationRequired', 'Invalid JWT signature', { Bearer: { error: 'BadJwtSignature' } });
45
+ }
46
+ }
47
+ return {
48
+ did: didDocument.id,
49
+ didDocument,
50
+ jwt,
51
+ };
52
+ };
53
+ }
54
+ async function verifyJwt(jwt, key) {
55
+ try {
56
+ return await crypto.verifySignature(key, jwt.message, jwt.signature, {
57
+ jwtAlg: jwt.header.alg,
58
+ allowMalleableSig: true,
59
+ });
60
+ }
61
+ catch (cause) {
62
+ throw new errors_js_1.LexServerAuthError('AuthenticationRequired', 'Could not verify JWT signature', { Bearer: { error: 'BadJwtSignature' } }, { cause });
63
+ }
64
+ }
65
+ function getAtprotoSigningKey(didDocument) {
66
+ try {
67
+ const key = didDocument.verificationMethod?.find(isAtprotoVerificationMethod, didDocument);
68
+ if (key?.publicKeyMultibase) {
69
+ if (key.type === 'EcdsaSecp256r1VerificationKey2019') {
70
+ const keyBytes = crypto.multibaseToBytes(key.publicKeyMultibase);
71
+ return crypto.formatDidKey(crypto.P256_JWT_ALG, keyBytes);
72
+ }
73
+ else if (key.type === 'EcdsaSecp256k1VerificationKey2019') {
74
+ const keyBytes = crypto.multibaseToBytes(key.publicKeyMultibase);
75
+ return crypto.formatDidKey(crypto.SECP256K1_JWT_ALG, keyBytes);
76
+ }
77
+ else if (key.type === 'Multikey') {
78
+ const parsed = crypto.parseMultikey(key.publicKeyMultibase);
79
+ return crypto.formatDidKey(parsed.jwtAlg, parsed.keyBytes);
80
+ }
81
+ }
82
+ }
83
+ catch {
84
+ // Invalid key, ignore
85
+ }
86
+ return null;
87
+ }
88
+ function isAtprotoVerificationMethod(vm) {
89
+ return typeof vm === 'object' && (0, did_1.matchesIdentifier)(this.id, 'atproto', vm.id);
90
+ }
91
+ async function parseJwtBearer(request, options) {
92
+ const authorization = request.headers.get('authorization');
93
+ if (!authorization?.startsWith(BEARER_PREFIX)) {
94
+ throw new errors_js_1.LexServerAuthError('AuthenticationRequired', 'Bearer token required', { Bearer: { error: 'MissingBearer' } });
95
+ }
96
+ const token = authorization.slice(BEARER_PREFIX.length).trim();
97
+ return parseJwt(token, options);
98
+ }
99
+ async function parseJwt(token, options) {
100
+ const { length, 0: headerB64, 1: payloadB64, 2: signatureB64, } = token.split('.');
101
+ if (length !== 3) {
102
+ throw new errors_js_1.LexServerAuthError('AuthenticationRequired', 'Invalid JWT token', { Bearer: { error: 'BadJwt' } });
103
+ }
104
+ let header;
105
+ try {
106
+ header = jsonFromBase64(headerB64, isHeaderObject);
107
+ }
108
+ catch (cause) {
109
+ throw new errors_js_1.LexServerAuthError('AuthenticationRequired', 'Invalid JWT token', { Bearer: { error: 'BadJwt' } }, { cause });
110
+ }
111
+ if (header.alg === 'none' ||
112
+ // service tokens are not OAuth 2.0 access tokens
113
+ // https://datatracker.ietf.org/doc/html/rfc9068
114
+ header.typ === 'at+jwt' ||
115
+ // "refresh+jwt" is a non-standard type used by the @atproto packages
116
+ header.typ === 'refresh+jwt' ||
117
+ // "DPoP" proofs are not meant to be used as service tokens
118
+ // https://datatracker.ietf.org/doc/html/rfc9449
119
+ header.typ === 'dpop+jwt') {
120
+ throw new errors_js_1.LexServerAuthError('AuthenticationRequired', 'Invalid JWT token', { Bearer: { error: 'BadJwt' } });
121
+ }
122
+ let payload;
123
+ try {
124
+ payload = jsonFromBase64(payloadB64, isPayloadObject);
125
+ }
126
+ catch (cause) {
127
+ throw new errors_js_1.LexServerAuthError('AuthenticationRequired', 'Invalid JWT token', { Bearer: { error: 'BadJwt' } }, { cause });
128
+ }
129
+ if (options.audience !== null && options.audience !== payload.aud) {
130
+ throw new errors_js_1.LexServerAuthError('AuthenticationRequired', 'Invalid audience', {
131
+ Bearer: { error: 'InvalidAudience' },
132
+ });
133
+ }
134
+ const now = Math.floor(Date.now() / 1000);
135
+ if (payload.nbf != null && now < payload.nbf) {
136
+ throw new errors_js_1.LexServerAuthError('AuthenticationRequired', 'JWT token not yet valid', { Bearer: { error: 'JwtNotYetValid' } });
137
+ }
138
+ if (now > payload.exp) {
139
+ throw new errors_js_1.LexServerAuthError('AuthenticationRequired', 'JWT token expired', { Bearer: { error: 'JwtExpired' } });
140
+ }
141
+ // Prevent issuer from generating very long-lived tokens
142
+ if (timeDiff(now, payload.exp) > options.maxAge ||
143
+ timeDiff(now, payload.iat) > options.maxAge) {
144
+ throw new errors_js_1.LexServerAuthError('AuthenticationRequired', 'JWT token too old', { Bearer: { error: 'JwtTooOld' } });
145
+ }
146
+ if (payload.lxm != null && typeof payload.lxm !== options.lxm) {
147
+ throw new errors_js_1.LexServerAuthError('AuthenticationRequired', 'Invalid JWT lexicon method ("lxm")', { Bearer: { error: 'BadJwtLexiconMethod' } });
148
+ }
149
+ if (payload.nonce != null && !(await (0, options.unique)(payload.nonce))) {
150
+ throw new errors_js_1.LexServerAuthError('AuthenticationRequired', 'Replay attack detected: nonce is not unique', { Bearer: { error: 'NonceNotUnique' } });
151
+ }
152
+ return {
153
+ header,
154
+ payload,
155
+ message: textEncoder.encode(`${headerB64}.${payloadB64}`),
156
+ signature: (0, lex_data_1.fromBase64)(signatureB64, 'base64url'),
157
+ };
158
+ }
159
+ const textEncoder = /*#__PURE__*/ new TextEncoder();
160
+ function isHeaderObject(obj) {
161
+ return ((0, lex_data_1.isPlainObject)(obj) &&
162
+ typeof obj.alg === 'string' &&
163
+ (obj.typ === undefined || typeof obj.typ === 'string'));
164
+ }
165
+ function isPayloadObject(obj) {
166
+ return ((0, lex_data_1.isPlainObject)(obj) &&
167
+ typeof obj.iss === 'string' &&
168
+ typeof obj.aud === 'string' &&
169
+ (obj.lxm === undefined || typeof obj.lxm === 'string') &&
170
+ (obj.nonce === undefined || typeof obj.nonce === 'string') &&
171
+ (obj.iat === undefined || isPositiveInt(obj.iat)) &&
172
+ (obj.nbf === undefined || isPositiveInt(obj.nbf)) &&
173
+ isPositiveInt(obj.exp) &&
174
+ (0, lex_schema_1.isDidString)(obj.iss) &&
175
+ (0, lex_schema_1.isDidString)(obj.aud));
176
+ }
177
+ function timeDiff(t1, t2) {
178
+ if (t2 === undefined)
179
+ return 0;
180
+ return Math.abs(t1 - t2);
181
+ }
182
+ function isPositiveInt(value) {
183
+ return typeof value === 'number' && Number.isInteger(value) && value > 0;
184
+ }
185
+ function jsonFromBase64(b64, isType) {
186
+ const obj = JSON.parse((0, lex_data_1.utf8FromBase64)(b64, 'base64url'));
187
+ if (isType(obj))
188
+ return obj;
189
+ throw new Error('Invalid type');
190
+ }
191
+ //# sourceMappingURL=service-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-auth.js","sourceRoot":"","sources":["../src/service-auth.ts"],"names":[],"mappings":"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","sourcesContent":["import * as crypto from '@atproto/crypto'\nimport {\n AtprotoDid,\n AtprotoDidDocument,\n Did,\n matchesIdentifier,\n} from '@atproto/did'\nimport { fromBase64, isPlainObject, utf8FromBase64 } from '@atproto/lex-data'\nimport { DidString, isDidString } from '@atproto/lex-schema'\nimport {\n CreateDidResolverOptions,\n createDidResolver,\n} from '@atproto-labs/did-resolver'\nimport { LexServerAuthError } from './errors.js'\nimport { LexRouterAuth } from './lex-server.js'\n\nconst BEARER_PREFIX = 'Bearer '\n\n/**\n * A function to check and record nonce uniqueness.\n */\nexport type UniqueNonceChecker = (nonce: string) => Promise<boolean>\n\nexport type ServiceAuthOptions = CreateDidResolverOptions & {\n /**\n * Expected audience (\"aud\") claim in the JWT token. Set to `null` to skip\n * audience verification (not recommended).\n */\n audience: null | DidString\n /**\n * Function to check and record nonce uniqueness. The value checked here must\n * be unique within {@link ServiceAuthOptions.maxAge} seconds before and after\n * the current time.\n *\n * @param nonce - The nonce to check.\n */\n unique: UniqueNonceChecker\n /**\n * Maximum age of the JWT token in seconds.\n *\n * @default 300 (5 minutes)\n */\n maxAge?: number\n}\n\nexport type ServiceAuthCredentials = {\n did: AtprotoDid\n didDocument: AtprotoDidDocument\n jwt: ParsedJwt\n}\n\n/**\n * Creates an authentication handler for LexRouter that verifies AT protocol\n * \"service auth\" JWT bearer tokens signed by decentralized identifiers (DIDs).\n */\nexport function serviceAuth({\n audience,\n maxAge = 5 * 60,\n unique,\n ...options\n}: ServiceAuthOptions): LexRouterAuth<ServiceAuthCredentials> {\n const didResolver = createDidResolver(options)\n\n return async ({ request, method }) => {\n const { signal } = request\n const jwt = await parseJwtBearer(request, {\n lxm: method.nsid,\n maxAge,\n audience,\n unique,\n })\n\n let didDocument: AtprotoDidDocument = await didResolver\n .resolve(jwt.payload.iss, { signal })\n .catch((cause) => {\n throw new LexServerAuthError(\n 'AuthenticationRequired',\n 'Could not resolve DID document',\n { Bearer: { error: 'DidResolutionFailed' } },\n { cause },\n )\n })\n\n const key = getAtprotoSigningKey(didDocument)\n\n if (!key || !(await verifyJwt(jwt, key))) {\n signal.throwIfAborted()\n\n // Try refreshing the DID document in case it was updated\n didDocument = await didResolver\n .resolve(jwt.payload.iss, { signal, noCache: true })\n .catch((cause) => {\n throw new LexServerAuthError(\n 'AuthenticationRequired',\n 'Could not resolve DID document',\n { Bearer: { error: 'DidResolutionFailed' } },\n { cause },\n )\n })\n\n // Verify again with the fresh key (if it changed)\n const keyFresh = getAtprotoSigningKey(didDocument)\n if (!keyFresh || key === keyFresh || !(await verifyJwt(jwt, keyFresh))) {\n throw new LexServerAuthError(\n 'AuthenticationRequired',\n 'Invalid JWT signature',\n { Bearer: { error: 'BadJwtSignature' } },\n )\n }\n }\n\n return {\n did: didDocument.id,\n didDocument,\n jwt,\n }\n }\n}\n\nasync function verifyJwt(jwt: ParsedJwt, key: Did<'key'>) {\n try {\n return await crypto.verifySignature(key, jwt.message, jwt.signature, {\n jwtAlg: jwt.header.alg,\n allowMalleableSig: true,\n })\n } catch (cause) {\n throw new LexServerAuthError(\n 'AuthenticationRequired',\n 'Could not verify JWT signature',\n { Bearer: { error: 'BadJwtSignature' } },\n { cause },\n )\n }\n}\n\nfunction getAtprotoSigningKey(\n didDocument: AtprotoDidDocument,\n): null | Did<'key'> {\n try {\n const key = didDocument.verificationMethod?.find(\n isAtprotoVerificationMethod,\n didDocument,\n )\n\n if (key?.publicKeyMultibase) {\n if (key.type === 'EcdsaSecp256r1VerificationKey2019') {\n const keyBytes = crypto.multibaseToBytes(key.publicKeyMultibase)\n return crypto.formatDidKey(crypto.P256_JWT_ALG, keyBytes)\n } else if (key.type === 'EcdsaSecp256k1VerificationKey2019') {\n const keyBytes = crypto.multibaseToBytes(key.publicKeyMultibase)\n return crypto.formatDidKey(crypto.SECP256K1_JWT_ALG, keyBytes)\n } else if (key.type === 'Multikey') {\n const parsed = crypto.parseMultikey(key.publicKeyMultibase)\n return crypto.formatDidKey(parsed.jwtAlg, parsed.keyBytes)\n }\n }\n } catch {\n // Invalid key, ignore\n }\n\n return null\n}\n\nfunction isAtprotoVerificationMethod<\n V extends string | { id: string; type: string; publicKeyMultibase?: string },\n>(\n this: AtprotoDidDocument,\n vm: V,\n): vm is Exclude<V, string> & {\n id: `${string}#atproto`\n} {\n return typeof vm === 'object' && matchesIdentifier(this.id, 'atproto', vm.id)\n}\n\nasync function parseJwtBearer(\n request: Request,\n options: ParseJwtOptions,\n): Promise<ParsedJwt> {\n const authorization = request.headers.get('authorization')\n if (!authorization?.startsWith(BEARER_PREFIX)) {\n throw new LexServerAuthError(\n 'AuthenticationRequired',\n 'Bearer token required',\n { Bearer: { error: 'MissingBearer' } },\n )\n }\n\n const token = authorization.slice(BEARER_PREFIX.length).trim()\n\n return parseJwt(token, options)\n}\n\nexport type ParseJwtOptions = {\n maxAge: number\n audience: null | DidString\n unique: UniqueNonceChecker\n lxm: string\n}\n\nexport type ParsedJwt = {\n header: HeaderObject\n payload: PayloadObject\n message: Uint8Array\n signature: Uint8Array\n}\n\nasync function parseJwt(\n token: string,\n options: ParseJwtOptions,\n): Promise<ParsedJwt> {\n const {\n length,\n 0: headerB64,\n 1: payloadB64,\n 2: signatureB64,\n } = token.split('.')\n if (length !== 3) {\n throw new LexServerAuthError(\n 'AuthenticationRequired',\n 'Invalid JWT token',\n { Bearer: { error: 'BadJwt' } },\n )\n }\n\n let header: HeaderObject\n try {\n header = jsonFromBase64(headerB64, isHeaderObject)\n } catch (cause) {\n throw new LexServerAuthError(\n 'AuthenticationRequired',\n 'Invalid JWT token',\n { Bearer: { error: 'BadJwt' } },\n { cause },\n )\n }\n\n if (\n header.alg === 'none' ||\n // service tokens are not OAuth 2.0 access tokens\n // https://datatracker.ietf.org/doc/html/rfc9068\n header.typ === 'at+jwt' ||\n // \"refresh+jwt\" is a non-standard type used by the @atproto packages\n header.typ === 'refresh+jwt' ||\n // \"DPoP\" proofs are not meant to be used as service tokens\n // https://datatracker.ietf.org/doc/html/rfc9449\n header.typ === 'dpop+jwt'\n ) {\n throw new LexServerAuthError(\n 'AuthenticationRequired',\n 'Invalid JWT token',\n { Bearer: { error: 'BadJwt' } },\n )\n }\n\n let payload: PayloadObject\n try {\n payload = jsonFromBase64(payloadB64, isPayloadObject)\n } catch (cause) {\n throw new LexServerAuthError(\n 'AuthenticationRequired',\n 'Invalid JWT token',\n { Bearer: { error: 'BadJwt' } },\n { cause },\n )\n }\n\n if (options.audience !== null && options.audience !== payload.aud) {\n throw new LexServerAuthError('AuthenticationRequired', 'Invalid audience', {\n Bearer: { error: 'InvalidAudience' },\n })\n }\n\n const now = Math.floor(Date.now() / 1000)\n\n if (payload.nbf != null && now < payload.nbf) {\n throw new LexServerAuthError(\n 'AuthenticationRequired',\n 'JWT token not yet valid',\n { Bearer: { error: 'JwtNotYetValid' } },\n )\n }\n\n if (now > payload.exp) {\n throw new LexServerAuthError(\n 'AuthenticationRequired',\n 'JWT token expired',\n { Bearer: { error: 'JwtExpired' } },\n )\n }\n\n // Prevent issuer from generating very long-lived tokens\n if (\n timeDiff(now, payload.exp) > options.maxAge ||\n timeDiff(now, payload.iat) > options.maxAge\n ) {\n throw new LexServerAuthError(\n 'AuthenticationRequired',\n 'JWT token too old',\n { Bearer: { error: 'JwtTooOld' } },\n )\n }\n\n if (payload.lxm != null && typeof payload.lxm !== options.lxm) {\n throw new LexServerAuthError(\n 'AuthenticationRequired',\n 'Invalid JWT lexicon method (\"lxm\")',\n { Bearer: { error: 'BadJwtLexiconMethod' } },\n )\n }\n\n if (payload.nonce != null && !(await (0, options.unique)(payload.nonce))) {\n throw new LexServerAuthError(\n 'AuthenticationRequired',\n 'Replay attack detected: nonce is not unique',\n { Bearer: { error: 'NonceNotUnique' } },\n )\n }\n\n return {\n header,\n payload,\n message: textEncoder.encode(`${headerB64}.${payloadB64}`),\n signature: fromBase64(signatureB64, 'base64url'),\n }\n}\n\nconst textEncoder = /*#__PURE__*/ new TextEncoder()\n\ntype HeaderObject = { alg: string; typ?: string }\nfunction isHeaderObject(obj: unknown): obj is HeaderObject {\n return (\n isPlainObject(obj) &&\n typeof obj.alg === 'string' &&\n (obj.typ === undefined || typeof obj.typ === 'string')\n )\n}\n\ntype PayloadObject = {\n iss: DidString\n aud: DidString\n exp: number\n iat?: number\n nbf?: number\n lxm?: string\n nonce?: string\n}\nexport function isPayloadObject(obj: unknown): obj is PayloadObject {\n return (\n isPlainObject(obj) &&\n typeof obj.iss === 'string' &&\n typeof obj.aud === 'string' &&\n (obj.lxm === undefined || typeof obj.lxm === 'string') &&\n (obj.nonce === undefined || typeof obj.nonce === 'string') &&\n (obj.iat === undefined || isPositiveInt(obj.iat)) &&\n (obj.nbf === undefined || isPositiveInt(obj.nbf)) &&\n isPositiveInt(obj.exp) &&\n isDidString(obj.iss) &&\n isDidString(obj.aud)\n )\n}\n\nfunction timeDiff(t1: number, t2?: number): number {\n if (t2 === undefined) return 0\n return Math.abs(t1 - t2)\n}\n\nfunction isPositiveInt(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value > 0\n}\n\nfunction jsonFromBase64<T>(b64: string, isType: (obj: unknown) => obj is T): T {\n const obj = JSON.parse(utf8FromBase64(b64, 'base64url'))\n if (isType(obj)) return obj\n throw new Error('Invalid type')\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/lex-server",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "license": "MIT",
5
5
  "description": "Request router for Atproto Lexicon protocols and schemas",
6
6
  "keywords": [
@@ -45,17 +45,20 @@
45
45
  "http-terminator": "^3.2.0",
46
46
  "tslib": "^2.8.1",
47
47
  "ws": "^8.18.3",
48
- "@atproto/lex-cbor": "0.0.5",
49
- "@atproto/lex-schema": "0.0.6",
50
- "@atproto/lex-data": "0.0.5",
51
- "@atproto/lex-json": "0.0.5"
48
+ "@atproto-labs/did-resolver": "0.2.5",
49
+ "@atproto/crypto": "0.4.5",
50
+ "@atproto/did": "0.2.4",
51
+ "@atproto/lex-cbor": "0.0.6",
52
+ "@atproto/lex-data": "0.0.6",
53
+ "@atproto/lex-json": "0.0.6",
54
+ "@atproto/lex-schema": "0.0.7"
52
55
  },
53
56
  "devDependencies": {
54
57
  "@types/ws": "^8.18.1",
55
58
  "@vitest/coverage-v8": "4.0.16",
56
59
  "vitest": "^4.0.16",
57
- "@atproto/lex": "0.0.8",
58
- "@atproto/lex-client": "0.0.6"
60
+ "@atproto/lex": "0.0.9",
61
+ "@atproto/lex-client": "0.0.7"
59
62
  },
60
63
  "scripts": {
61
64
  "build": "tsc --build tsconfig.build.json",
package/src/index.ts CHANGED
@@ -6,3 +6,4 @@ export {
6
6
 
7
7
  export * from './errors.js'
8
8
  export * from './lex-server.js'
9
+ export * from './service-auth.js'
@@ -287,7 +287,7 @@ describe('Authentication', () => {
287
287
  function createBasicAuth(allowed: {
288
288
  username: string
289
289
  password: string
290
- }): LexRouterAuth<typeof io.example.authTest, BasicAuthCredentials> {
290
+ }): LexRouterAuth<BasicAuthCredentials> {
291
291
  return async ({ request }) => {
292
292
  const header = request.headers.get('authorization') ?? ''
293
293
  if (!header.startsWith('Basic ')) {
package/src/lex-server.ts CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  import { drainWebsocket } from './lib/drain-websocket.js'
20
20
 
21
21
  type Awaitable<T> = T | Promise<T>
22
- type LexMethod = Query | Procedure | Subscription
22
+ export type LexMethod = Query | Procedure | Subscription
23
23
 
24
24
  export type NetAddr = {
25
25
  hostname: string
@@ -81,7 +81,7 @@ export type LexRouterMethodConfig<
81
81
  Credentials = unknown,
82
82
  > = {
83
83
  handler: LexRouterMethodHandler<Method, Credentials>
84
- auth: LexRouterAuth<Method, Credentials>
84
+ auth: LexRouterAuth<Credentials, Method>
85
85
  }
86
86
 
87
87
  export type LexRouterSubscriptionHandler<
@@ -96,18 +96,19 @@ export type LexRouterSubscriptionConfig<
96
96
  Credentials = unknown,
97
97
  > = {
98
98
  handler: LexRouterSubscriptionHandler<Method, Credentials>
99
- auth: LexRouterAuth<Method, Credentials>
99
+ auth: LexRouterAuth<Credentials, Method>
100
100
  }
101
101
 
102
102
  export type LexRouterAuthContext<Method extends LexMethod = LexMethod> = {
103
+ method: Method
103
104
  params: InferMethodParams<Method>
104
105
  request: Request
105
106
  connection?: ConnectionInfo
106
107
  }
107
108
 
108
109
  export type LexRouterAuth<
109
- Method extends LexMethod = LexMethod,
110
110
  Credentials = unknown,
111
+ Method extends LexMethod = LexMethod,
111
112
  > = (ctx: LexRouterAuthContext<Method>) => Credentials | Promise<Credentials>
112
113
 
113
114
  export type LexErrorHandlerContext = {
@@ -187,7 +188,7 @@ export class LexRouter {
187
188
  private buildMethodHandler<Method extends Query | Procedure, Credentials>(
188
189
  method: Method,
189
190
  methodHandler: LexRouterMethodHandler<Method, Credentials>,
190
- auth?: LexRouterAuth<Method, Credentials>,
191
+ auth?: LexRouterAuth<Credentials, Method>,
191
192
  ): Handler {
192
193
  const getInput = (
193
194
  method.type === 'procedure'
@@ -215,7 +216,7 @@ export class LexRouter {
215
216
  const params = method.parameters.fromURLSearchParams(url.searchParams)
216
217
 
217
218
  const credentials = auth
218
- ? await auth({ params, request, connection })
219
+ ? await auth({ method, params, request, connection })
219
220
  : (undefined as Credentials)
220
221
 
221
222
  const input = await getInput(request)
@@ -258,7 +259,7 @@ export class LexRouter {
258
259
  private buildSubscriptionHandler<Method extends Subscription, Credentials>(
259
260
  method: Method,
260
261
  methodHandler: LexRouterSubscriptionHandler<Method, Credentials>,
261
- auth?: LexRouterAuth<Method, Credentials>,
262
+ auth?: LexRouterAuth<Credentials, Method>,
262
263
  ): Handler {
263
264
  const {
264
265
  onHandlerError,
@@ -334,7 +335,7 @@ export class LexRouter {
334
335
  )
335
336
 
336
337
  const credentials: Credentials = auth
337
- ? await auth({ params, request, connection })
338
+ ? await auth({ method, params, request, connection })
338
339
  : (undefined as Credentials)
339
340
 
340
341
  signal.throwIfAborted()
@@ -0,0 +1,375 @@
1
+ import * as crypto from '@atproto/crypto'
2
+ import {
3
+ AtprotoDid,
4
+ AtprotoDidDocument,
5
+ Did,
6
+ matchesIdentifier,
7
+ } from '@atproto/did'
8
+ import { fromBase64, isPlainObject, utf8FromBase64 } from '@atproto/lex-data'
9
+ import { DidString, isDidString } from '@atproto/lex-schema'
10
+ import {
11
+ CreateDidResolverOptions,
12
+ createDidResolver,
13
+ } from '@atproto-labs/did-resolver'
14
+ import { LexServerAuthError } from './errors.js'
15
+ import { LexRouterAuth } from './lex-server.js'
16
+
17
+ const BEARER_PREFIX = 'Bearer '
18
+
19
+ /**
20
+ * A function to check and record nonce uniqueness.
21
+ */
22
+ export type UniqueNonceChecker = (nonce: string) => Promise<boolean>
23
+
24
+ export type ServiceAuthOptions = CreateDidResolverOptions & {
25
+ /**
26
+ * Expected audience ("aud") claim in the JWT token. Set to `null` to skip
27
+ * audience verification (not recommended).
28
+ */
29
+ audience: null | DidString
30
+ /**
31
+ * Function to check and record nonce uniqueness. The value checked here must
32
+ * be unique within {@link ServiceAuthOptions.maxAge} seconds before and after
33
+ * the current time.
34
+ *
35
+ * @param nonce - The nonce to check.
36
+ */
37
+ unique: UniqueNonceChecker
38
+ /**
39
+ * Maximum age of the JWT token in seconds.
40
+ *
41
+ * @default 300 (5 minutes)
42
+ */
43
+ maxAge?: number
44
+ }
45
+
46
+ export type ServiceAuthCredentials = {
47
+ did: AtprotoDid
48
+ didDocument: AtprotoDidDocument
49
+ jwt: ParsedJwt
50
+ }
51
+
52
+ /**
53
+ * Creates an authentication handler for LexRouter that verifies AT protocol
54
+ * "service auth" JWT bearer tokens signed by decentralized identifiers (DIDs).
55
+ */
56
+ export function serviceAuth({
57
+ audience,
58
+ maxAge = 5 * 60,
59
+ unique,
60
+ ...options
61
+ }: ServiceAuthOptions): LexRouterAuth<ServiceAuthCredentials> {
62
+ const didResolver = createDidResolver(options)
63
+
64
+ return async ({ request, method }) => {
65
+ const { signal } = request
66
+ const jwt = await parseJwtBearer(request, {
67
+ lxm: method.nsid,
68
+ maxAge,
69
+ audience,
70
+ unique,
71
+ })
72
+
73
+ let didDocument: AtprotoDidDocument = await didResolver
74
+ .resolve(jwt.payload.iss, { signal })
75
+ .catch((cause) => {
76
+ throw new LexServerAuthError(
77
+ 'AuthenticationRequired',
78
+ 'Could not resolve DID document',
79
+ { Bearer: { error: 'DidResolutionFailed' } },
80
+ { cause },
81
+ )
82
+ })
83
+
84
+ const key = getAtprotoSigningKey(didDocument)
85
+
86
+ if (!key || !(await verifyJwt(jwt, key))) {
87
+ signal.throwIfAborted()
88
+
89
+ // Try refreshing the DID document in case it was updated
90
+ didDocument = await didResolver
91
+ .resolve(jwt.payload.iss, { signal, noCache: true })
92
+ .catch((cause) => {
93
+ throw new LexServerAuthError(
94
+ 'AuthenticationRequired',
95
+ 'Could not resolve DID document',
96
+ { Bearer: { error: 'DidResolutionFailed' } },
97
+ { cause },
98
+ )
99
+ })
100
+
101
+ // Verify again with the fresh key (if it changed)
102
+ const keyFresh = getAtprotoSigningKey(didDocument)
103
+ if (!keyFresh || key === keyFresh || !(await verifyJwt(jwt, keyFresh))) {
104
+ throw new LexServerAuthError(
105
+ 'AuthenticationRequired',
106
+ 'Invalid JWT signature',
107
+ { Bearer: { error: 'BadJwtSignature' } },
108
+ )
109
+ }
110
+ }
111
+
112
+ return {
113
+ did: didDocument.id,
114
+ didDocument,
115
+ jwt,
116
+ }
117
+ }
118
+ }
119
+
120
+ async function verifyJwt(jwt: ParsedJwt, key: Did<'key'>) {
121
+ try {
122
+ return await crypto.verifySignature(key, jwt.message, jwt.signature, {
123
+ jwtAlg: jwt.header.alg,
124
+ allowMalleableSig: true,
125
+ })
126
+ } catch (cause) {
127
+ throw new LexServerAuthError(
128
+ 'AuthenticationRequired',
129
+ 'Could not verify JWT signature',
130
+ { Bearer: { error: 'BadJwtSignature' } },
131
+ { cause },
132
+ )
133
+ }
134
+ }
135
+
136
+ function getAtprotoSigningKey(
137
+ didDocument: AtprotoDidDocument,
138
+ ): null | Did<'key'> {
139
+ try {
140
+ const key = didDocument.verificationMethod?.find(
141
+ isAtprotoVerificationMethod,
142
+ didDocument,
143
+ )
144
+
145
+ if (key?.publicKeyMultibase) {
146
+ if (key.type === 'EcdsaSecp256r1VerificationKey2019') {
147
+ const keyBytes = crypto.multibaseToBytes(key.publicKeyMultibase)
148
+ return crypto.formatDidKey(crypto.P256_JWT_ALG, keyBytes)
149
+ } else if (key.type === 'EcdsaSecp256k1VerificationKey2019') {
150
+ const keyBytes = crypto.multibaseToBytes(key.publicKeyMultibase)
151
+ return crypto.formatDidKey(crypto.SECP256K1_JWT_ALG, keyBytes)
152
+ } else if (key.type === 'Multikey') {
153
+ const parsed = crypto.parseMultikey(key.publicKeyMultibase)
154
+ return crypto.formatDidKey(parsed.jwtAlg, parsed.keyBytes)
155
+ }
156
+ }
157
+ } catch {
158
+ // Invalid key, ignore
159
+ }
160
+
161
+ return null
162
+ }
163
+
164
+ function isAtprotoVerificationMethod<
165
+ V extends string | { id: string; type: string; publicKeyMultibase?: string },
166
+ >(
167
+ this: AtprotoDidDocument,
168
+ vm: V,
169
+ ): vm is Exclude<V, string> & {
170
+ id: `${string}#atproto`
171
+ } {
172
+ return typeof vm === 'object' && matchesIdentifier(this.id, 'atproto', vm.id)
173
+ }
174
+
175
+ async function parseJwtBearer(
176
+ request: Request,
177
+ options: ParseJwtOptions,
178
+ ): Promise<ParsedJwt> {
179
+ const authorization = request.headers.get('authorization')
180
+ if (!authorization?.startsWith(BEARER_PREFIX)) {
181
+ throw new LexServerAuthError(
182
+ 'AuthenticationRequired',
183
+ 'Bearer token required',
184
+ { Bearer: { error: 'MissingBearer' } },
185
+ )
186
+ }
187
+
188
+ const token = authorization.slice(BEARER_PREFIX.length).trim()
189
+
190
+ return parseJwt(token, options)
191
+ }
192
+
193
+ export type ParseJwtOptions = {
194
+ maxAge: number
195
+ audience: null | DidString
196
+ unique: UniqueNonceChecker
197
+ lxm: string
198
+ }
199
+
200
+ export type ParsedJwt = {
201
+ header: HeaderObject
202
+ payload: PayloadObject
203
+ message: Uint8Array
204
+ signature: Uint8Array
205
+ }
206
+
207
+ async function parseJwt(
208
+ token: string,
209
+ options: ParseJwtOptions,
210
+ ): Promise<ParsedJwt> {
211
+ const {
212
+ length,
213
+ 0: headerB64,
214
+ 1: payloadB64,
215
+ 2: signatureB64,
216
+ } = token.split('.')
217
+ if (length !== 3) {
218
+ throw new LexServerAuthError(
219
+ 'AuthenticationRequired',
220
+ 'Invalid JWT token',
221
+ { Bearer: { error: 'BadJwt' } },
222
+ )
223
+ }
224
+
225
+ let header: HeaderObject
226
+ try {
227
+ header = jsonFromBase64(headerB64, isHeaderObject)
228
+ } catch (cause) {
229
+ throw new LexServerAuthError(
230
+ 'AuthenticationRequired',
231
+ 'Invalid JWT token',
232
+ { Bearer: { error: 'BadJwt' } },
233
+ { cause },
234
+ )
235
+ }
236
+
237
+ if (
238
+ header.alg === 'none' ||
239
+ // service tokens are not OAuth 2.0 access tokens
240
+ // https://datatracker.ietf.org/doc/html/rfc9068
241
+ header.typ === 'at+jwt' ||
242
+ // "refresh+jwt" is a non-standard type used by the @atproto packages
243
+ header.typ === 'refresh+jwt' ||
244
+ // "DPoP" proofs are not meant to be used as service tokens
245
+ // https://datatracker.ietf.org/doc/html/rfc9449
246
+ header.typ === 'dpop+jwt'
247
+ ) {
248
+ throw new LexServerAuthError(
249
+ 'AuthenticationRequired',
250
+ 'Invalid JWT token',
251
+ { Bearer: { error: 'BadJwt' } },
252
+ )
253
+ }
254
+
255
+ let payload: PayloadObject
256
+ try {
257
+ payload = jsonFromBase64(payloadB64, isPayloadObject)
258
+ } catch (cause) {
259
+ throw new LexServerAuthError(
260
+ 'AuthenticationRequired',
261
+ 'Invalid JWT token',
262
+ { Bearer: { error: 'BadJwt' } },
263
+ { cause },
264
+ )
265
+ }
266
+
267
+ if (options.audience !== null && options.audience !== payload.aud) {
268
+ throw new LexServerAuthError('AuthenticationRequired', 'Invalid audience', {
269
+ Bearer: { error: 'InvalidAudience' },
270
+ })
271
+ }
272
+
273
+ const now = Math.floor(Date.now() / 1000)
274
+
275
+ if (payload.nbf != null && now < payload.nbf) {
276
+ throw new LexServerAuthError(
277
+ 'AuthenticationRequired',
278
+ 'JWT token not yet valid',
279
+ { Bearer: { error: 'JwtNotYetValid' } },
280
+ )
281
+ }
282
+
283
+ if (now > payload.exp) {
284
+ throw new LexServerAuthError(
285
+ 'AuthenticationRequired',
286
+ 'JWT token expired',
287
+ { Bearer: { error: 'JwtExpired' } },
288
+ )
289
+ }
290
+
291
+ // Prevent issuer from generating very long-lived tokens
292
+ if (
293
+ timeDiff(now, payload.exp) > options.maxAge ||
294
+ timeDiff(now, payload.iat) > options.maxAge
295
+ ) {
296
+ throw new LexServerAuthError(
297
+ 'AuthenticationRequired',
298
+ 'JWT token too old',
299
+ { Bearer: { error: 'JwtTooOld' } },
300
+ )
301
+ }
302
+
303
+ if (payload.lxm != null && typeof payload.lxm !== options.lxm) {
304
+ throw new LexServerAuthError(
305
+ 'AuthenticationRequired',
306
+ 'Invalid JWT lexicon method ("lxm")',
307
+ { Bearer: { error: 'BadJwtLexiconMethod' } },
308
+ )
309
+ }
310
+
311
+ if (payload.nonce != null && !(await (0, options.unique)(payload.nonce))) {
312
+ throw new LexServerAuthError(
313
+ 'AuthenticationRequired',
314
+ 'Replay attack detected: nonce is not unique',
315
+ { Bearer: { error: 'NonceNotUnique' } },
316
+ )
317
+ }
318
+
319
+ return {
320
+ header,
321
+ payload,
322
+ message: textEncoder.encode(`${headerB64}.${payloadB64}`),
323
+ signature: fromBase64(signatureB64, 'base64url'),
324
+ }
325
+ }
326
+
327
+ const textEncoder = /*#__PURE__*/ new TextEncoder()
328
+
329
+ type HeaderObject = { alg: string; typ?: string }
330
+ function isHeaderObject(obj: unknown): obj is HeaderObject {
331
+ return (
332
+ isPlainObject(obj) &&
333
+ typeof obj.alg === 'string' &&
334
+ (obj.typ === undefined || typeof obj.typ === 'string')
335
+ )
336
+ }
337
+
338
+ type PayloadObject = {
339
+ iss: DidString
340
+ aud: DidString
341
+ exp: number
342
+ iat?: number
343
+ nbf?: number
344
+ lxm?: string
345
+ nonce?: string
346
+ }
347
+ export function isPayloadObject(obj: unknown): obj is PayloadObject {
348
+ return (
349
+ isPlainObject(obj) &&
350
+ typeof obj.iss === 'string' &&
351
+ typeof obj.aud === 'string' &&
352
+ (obj.lxm === undefined || typeof obj.lxm === 'string') &&
353
+ (obj.nonce === undefined || typeof obj.nonce === 'string') &&
354
+ (obj.iat === undefined || isPositiveInt(obj.iat)) &&
355
+ (obj.nbf === undefined || isPositiveInt(obj.nbf)) &&
356
+ isPositiveInt(obj.exp) &&
357
+ isDidString(obj.iss) &&
358
+ isDidString(obj.aud)
359
+ )
360
+ }
361
+
362
+ function timeDiff(t1: number, t2?: number): number {
363
+ if (t2 === undefined) return 0
364
+ return Math.abs(t1 - t2)
365
+ }
366
+
367
+ function isPositiveInt(value: unknown): value is number {
368
+ return typeof value === 'number' && Number.isInteger(value) && value > 0
369
+ }
370
+
371
+ function jsonFromBase64<T>(b64: string, isType: (obj: unknown) => obj is T): T {
372
+ const obj = JSON.parse(utf8FromBase64(b64, 'base64url'))
373
+ if (isType(obj)) return obj
374
+ throw new Error('Invalid type')
375
+ }