mirror of
https://github.com/better-auth/better-auth.git
synced 2026-05-25 08:31:37 -05:00
fix issues
This commit is contained in:
@@ -359,6 +359,7 @@ The examples above use `withMcpAuth` which requires the Better Auth instance to
|
||||
}) // [!code highlight]
|
||||
|
||||
const mcpServer = new McpServer({ name: "my-server", version: "1.0.0" })
|
||||
const app = express() // your HTTP framework
|
||||
|
||||
app.post("/mcp", auth.handler(async (req, session) => { // [!code highlight]
|
||||
const transport = new StreamableHTTPServerTransport({
|
||||
@@ -402,9 +403,9 @@ The examples above use `withMcpAuth` which requires the Better Auth instance to
|
||||
type: "string",
|
||||
required: false
|
||||
},
|
||||
allowedOrigins: {
|
||||
description: "Allowed CORS origin(s). Defaults to the authURL origin. Set to '*' to allow all origins (not recommended for production).",
|
||||
type: "string | string[]",
|
||||
allowedOrigin: {
|
||||
description: "Allowed CORS origin. Defaults to the authURL origin. Set to '*' to allow all origins (not recommended for production).",
|
||||
type: "string",
|
||||
required: false
|
||||
},
|
||||
fetch: {
|
||||
|
||||
@@ -32,14 +32,18 @@ export function mcpAuthHono(options: McpAuthClientOptions): {
|
||||
} {
|
||||
const client = createMcpAuthClient(options);
|
||||
|
||||
const resourceBase = options.resource ?? client.authURL;
|
||||
|
||||
const middleware: HonoMiddleware = async (c, next) => {
|
||||
const token = c.req.header("Authorization")?.replace("Bearer ", "");
|
||||
const authHeader = c.req.header("Authorization");
|
||||
const token = authHeader?.startsWith("Bearer ")
|
||||
? authHeader.slice(7)
|
||||
: undefined;
|
||||
if (!token) {
|
||||
c.header(
|
||||
"WWW-Authenticate",
|
||||
`Bearer resource_metadata="${client.authURL}/.well-known/oauth-protected-resource"`,
|
||||
`Bearer resource_metadata="${resourceBase}/.well-known/oauth-protected-resource"`,
|
||||
);
|
||||
c.header("Access-Control-Expose-Headers", "WWW-Authenticate");
|
||||
return c.json(
|
||||
{
|
||||
jsonrpc: "2.0",
|
||||
@@ -57,7 +61,7 @@ export function mcpAuthHono(options: McpAuthClientOptions): {
|
||||
if (!session) {
|
||||
c.header(
|
||||
"WWW-Authenticate",
|
||||
`Bearer resource_metadata="${client.authURL}/.well-known/oauth-protected-resource"`,
|
||||
`Bearer resource_metadata="${resourceBase}/.well-known/oauth-protected-resource"`,
|
||||
);
|
||||
return c.json(
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export interface McpAuthClientOptions {
|
||||
authURL: string;
|
||||
resource?: string;
|
||||
allowedOrigins?: string | string[];
|
||||
allowedOrigin?: string;
|
||||
fetch?: typeof globalThis.fetch;
|
||||
}
|
||||
|
||||
@@ -65,13 +65,11 @@ export interface McpAuthClient {
|
||||
|
||||
function buildCorsHeaders(
|
||||
authURL: string,
|
||||
allowedOrigins?: string | string[],
|
||||
allowedOrigin?: string,
|
||||
): Record<string, string> {
|
||||
let origin: string;
|
||||
if (allowedOrigins) {
|
||||
origin = Array.isArray(allowedOrigins)
|
||||
? allowedOrigins.join(", ")
|
||||
: allowedOrigins;
|
||||
if (allowedOrigin) {
|
||||
origin = allowedOrigin;
|
||||
} else {
|
||||
try {
|
||||
origin = new URL(authURL).origin;
|
||||
@@ -110,7 +108,6 @@ function make401Response(authURL: string, resource?: string): Response {
|
||||
status: 401,
|
||||
headers: {
|
||||
"WWW-Authenticate": wwwAuth,
|
||||
"Access-Control-Expose-Headers": "WWW-Authenticate",
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -129,13 +126,11 @@ function send401Node(
|
||||
|
||||
if (typeof res.set === "function") {
|
||||
res.set("WWW-Authenticate", wwwAuth);
|
||||
res.set("Access-Control-Expose-Headers", "WWW-Authenticate");
|
||||
res.status?.(401).json(JSON.parse(body));
|
||||
} else if (typeof res.writeHead === "function") {
|
||||
res.writeHead(401, {
|
||||
"Content-Type": "application/json",
|
||||
"WWW-Authenticate": wwwAuth,
|
||||
"Access-Control-Expose-Headers": "WWW-Authenticate",
|
||||
});
|
||||
res.end?.(body);
|
||||
}
|
||||
@@ -148,7 +143,7 @@ export function createMcpAuthClient(
|
||||
? options.authURL.slice(0, -1)
|
||||
: options.authURL;
|
||||
const fetchFn = options.fetch ?? globalThis.fetch;
|
||||
const corsHeaders = buildCorsHeaders(authURL, options.allowedOrigins);
|
||||
const corsHeaders = buildCorsHeaders(authURL, options.allowedOrigin);
|
||||
|
||||
const verifyToken = async (token: string): Promise<McpSession | null> => {
|
||||
try {
|
||||
|
||||
@@ -145,7 +145,7 @@ describe("mcp-client", async () => {
|
||||
it("should allow custom CORS origins", async () => {
|
||||
const client = createMcpAuthClient({
|
||||
authURL,
|
||||
allowedOrigins: "https://myapp.com",
|
||||
allowedOrigin: "https://myapp.com",
|
||||
});
|
||||
|
||||
const protectedHandler = client.handler(async () => {
|
||||
@@ -175,7 +175,7 @@ describe("mcp-client", async () => {
|
||||
scopes: "openid profile email",
|
||||
};
|
||||
|
||||
const mockFetch: typeof fetch = async (input) => {
|
||||
const mockFetch = (async (input: RequestInfo | URL) => {
|
||||
const url = typeof input === "string" ? input : (input as Request).url;
|
||||
if (url.includes("/mcp/get-session")) {
|
||||
return new Response(JSON.stringify(mockSession), {
|
||||
@@ -184,7 +184,7 @@ describe("mcp-client", async () => {
|
||||
});
|
||||
}
|
||||
return new Response("Not Found", { status: 404 });
|
||||
};
|
||||
}) as typeof fetch;
|
||||
|
||||
it("should return session for a valid token", async () => {
|
||||
const client = createMcpAuthClient({
|
||||
@@ -401,7 +401,7 @@ describe("mcp-client", async () => {
|
||||
|
||||
const mockReq = {
|
||||
headers: { authorization: "Bearer invalid-token-for-test" },
|
||||
mcpSession: undefined as unknown,
|
||||
mcpSession: undefined as McpSession | undefined,
|
||||
};
|
||||
const mockRes = {
|
||||
set: (_key: string, _value: string) => {},
|
||||
|
||||
Reference in New Issue
Block a user