Skip to content

Commit af025e2

Browse files
committed
Include AuthInfo from bearer validation in transport request handler
1 parent 66e1508 commit af025e2

File tree

3 files changed

+22
-10
lines changed

3 files changed

+22
-10
lines changed

src/server/sse.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Transport } from "../shared/transport.js";
44
import { JSONRPCMessage, JSONRPCMessageSchema } from "../types.js";
55
import getRawBody from "raw-body";
66
import contentType from "content-type";
7+
import { AuthInfo } from "./auth/types.js";
78

89
const MAXIMUM_MESSAGE_SIZE = "4mb";
910

@@ -18,7 +19,7 @@ export class SSEServerTransport implements Transport {
1819

1920
onclose?: () => void;
2021
onerror?: (error: Error) => void;
21-
onmessage?: (message: JSONRPCMessage) => void;
22+
onmessage?: (message: JSONRPCMessage, authInfo?: AuthInfo) => void;
2223

2324
/**
2425
* Creates a new SSE server transport, which will direct the client to POST messages to the relative or absolute URL identified by `_endpoint`.
@@ -66,7 +67,7 @@ export class SSEServerTransport implements Transport {
6667
* This should be called when a POST request is made to send a message to the server.
6768
*/
6869
async handlePostMessage(
69-
req: IncomingMessage,
70+
req: IncomingMessage & { auth?: AuthInfo },
7071
res: ServerResponse,
7172
parsedBody?: unknown,
7273
): Promise<void> {
@@ -75,6 +76,7 @@ export class SSEServerTransport implements Transport {
7576
res.writeHead(500).end(message);
7677
throw new Error(message);
7778
}
79+
const authInfo: AuthInfo | undefined = req.auth;
7880

7981
let body: string | unknown;
8082
try {
@@ -94,7 +96,7 @@ export class SSEServerTransport implements Transport {
9496
}
9597

9698
try {
97-
await this.handleMessage(typeof body === 'string' ? JSON.parse(body) : body);
99+
await this.handleMessage(typeof body === 'string' ? JSON.parse(body) : body, authInfo);
98100
} catch {
99101
res.writeHead(400).end(`Invalid message: ${body}`);
100102
return;
@@ -106,7 +108,7 @@ export class SSEServerTransport implements Transport {
106108
/**
107109
* Handle a client message, regardless of how it arrived. This can be used to inform the server of messages that arrive via a means different than HTTP POST.
108110
*/
109-
async handleMessage(message: unknown): Promise<void> {
111+
async handleMessage(message: unknown, authInfo?: AuthInfo): Promise<void> {
110112
let parsedMessage: JSONRPCMessage;
111113
try {
112114
parsedMessage = JSONRPCMessageSchema.parse(message);
@@ -115,7 +117,7 @@ export class SSEServerTransport implements Transport {
115117
throw error;
116118
}
117119

118-
this.onmessage?.(parsedMessage);
120+
this.onmessage?.(parsedMessage, authInfo);
119121
}
120122

121123
async close(): Promise<void> {

src/shared/protocol.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
ServerCapabilities,
2020
} from "../types.js";
2121
import { Transport } from "./transport.js";
22+
import { AuthInfo } from "../server/auth/types.js";
2223

2324
/**
2425
* Callback for progress notifications.
@@ -88,6 +89,11 @@ export type RequestHandlerExtra = {
8889
* An abort signal used to communicate if the request was cancelled from the sender's side.
8990
*/
9091
signal: AbortSignal;
92+
93+
/**
94+
* Information about a validated access token, provided to request handlers.
95+
*/
96+
authInfo?: AuthInfo;
9197
};
9298

9399
/**
@@ -232,11 +238,11 @@ export abstract class Protocol<
232238
this._onerror(error);
233239
};
234240

235-
this._transport.onmessage = (message) => {
241+
this._transport.onmessage = (message, authInfo) => {
236242
if (!("method" in message)) {
237243
this._onresponse(message);
238244
} else if ("id" in message) {
239-
this._onrequest(message);
245+
this._onrequest(message, authInfo);
240246
} else {
241247
this._onnotification(message);
242248
}
@@ -282,7 +288,7 @@ export abstract class Protocol<
282288
);
283289
}
284290

285-
private _onrequest(request: JSONRPCRequest): void {
291+
private _onrequest(request: JSONRPCRequest, authInfo?: AuthInfo): void {
286292
const handler =
287293
this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
288294

@@ -309,7 +315,7 @@ export abstract class Protocol<
309315

310316
// Starting with Promise.resolve() puts any synchronous errors into the monad as well.
311317
Promise.resolve()
312-
.then(() => handler(request, { signal: abortController.signal }))
318+
.then(() => handler(request, { signal: abortController.signal, authInfo }))
313319
.then(
314320
(result) => {
315321
if (abortController.signal.aborted) {

src/shared/transport.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { AuthInfo } from "../server/auth/types.js";
12
import { JSONRPCMessage } from "../types.js";
23

34
/**
@@ -39,6 +40,9 @@ export interface Transport {
3940

4041
/**
4142
* Callback for when a message (request or response) is received over the connection.
43+
*
44+
* Includes the authInfo if the transport is authenticated.
45+
*
4246
*/
43-
onmessage?: (message: JSONRPCMessage) => void;
47+
onmessage?: (message: JSONRPCMessage, authInfo?: AuthInfo) => void;
4448
}

0 commit comments

Comments
 (0)