mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-10 04:19:32 +00:00
Merge remote-tracking branch 'upstream' into v1.3.8-staging
This commit is contained in:
@@ -66,6 +66,17 @@ import { auth } from "../../../lib/auth";
|
|||||||
export const GET = oAuthDiscoveryMetadata(auth);
|
export const GET = oAuthDiscoveryMetadata(auth);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### OAuth Protected Resource Metadata
|
||||||
|
|
||||||
|
Add a route to expose protected resource metadata for MCP clients:
|
||||||
|
|
||||||
|
```ts title=".well-known/oauth-authorization-server/route.ts"
|
||||||
|
import { oAuthProtectedResourceMetadata } from "better-auth/plugins";
|
||||||
|
import { auth } from "@/lib/auth";
|
||||||
|
|
||||||
|
export const GET = oAuthProtectedResourceMetadata(auth);
|
||||||
|
```
|
||||||
|
|
||||||
### MCP Session Handling
|
### MCP Session Handling
|
||||||
|
|
||||||
You can use the helper function `withMcpAuth` to get the session and handle unauthenticated calls automatically.
|
You can use the helper function `withMcpAuth` to get the session and handle unauthenticated calls automatically.
|
||||||
|
|||||||
@@ -83,6 +83,27 @@ export const getMCPProviderMetadata = (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getMCPProtectedResourceMetadata = (
|
||||||
|
ctx: GenericEndpointContext,
|
||||||
|
options?: OIDCOptions,
|
||||||
|
) => {
|
||||||
|
const baseURL = ctx.context.baseURL;
|
||||||
|
|
||||||
|
return {
|
||||||
|
resource: baseURL,
|
||||||
|
authorization_servers: [baseURL],
|
||||||
|
jwks_uri: options?.metadata?.jwks_uri ?? `${baseURL}/mcp/jwks`,
|
||||||
|
scopes_supported: options?.metadata?.scopes_supported ?? [
|
||||||
|
"openid",
|
||||||
|
"profile",
|
||||||
|
"email",
|
||||||
|
"offline_access",
|
||||||
|
],
|
||||||
|
bearer_methods_supported: ["header"],
|
||||||
|
resource_signing_alg_values_supported: ["RS256", "none"],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const mcp = (options: MCPOptions) => {
|
export const mcp = (options: MCPOptions) => {
|
||||||
const opts = {
|
const opts = {
|
||||||
codeExpiresIn: 600,
|
codeExpiresIn: 600,
|
||||||
@@ -168,6 +189,19 @@ export const mcp = (options: MCPOptions) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
getMCPProtectedResource: createAuthEndpoint(
|
||||||
|
"/.well-known/oauth-protected-resource",
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
metadata: {
|
||||||
|
client: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async (c) => {
|
||||||
|
const metadata = getMCPProtectedResourceMetadata(c, options);
|
||||||
|
return c.json(metadata);
|
||||||
|
},
|
||||||
|
),
|
||||||
mcpOAuthAuthroize: createAuthEndpoint(
|
mcpOAuthAuthroize: createAuthEndpoint(
|
||||||
"/mcp/authorize",
|
"/mcp/authorize",
|
||||||
{
|
{
|
||||||
@@ -912,7 +946,7 @@ export const withMcpAuth = <
|
|||||||
const session = await auth.api.getMcpSession({
|
const session = await auth.api.getMcpSession({
|
||||||
headers: req.headers,
|
headers: req.headers,
|
||||||
});
|
});
|
||||||
const wwwAuthenticateValue = `Bearer resource_metadata=${baseURL}/api/auth/.well-known/oauth-authorization-server`;
|
const wwwAuthenticateValue = `Bearer resource_metadata=${baseURL}/api/auth/.well-known/oauth-protected-resource`;
|
||||||
if (!session) {
|
if (!session) {
|
||||||
return Response.json(
|
return Response.json(
|
||||||
{
|
{
|
||||||
@@ -959,3 +993,27 @@ export const oAuthDiscoveryMetadata = <
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const oAuthProtectedResourceMetadata = <
|
||||||
|
Auth extends {
|
||||||
|
api: {
|
||||||
|
getMCPProtectedResource: (...args: any) => any;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
>(
|
||||||
|
auth: Auth,
|
||||||
|
) => {
|
||||||
|
return async (request: Request) => {
|
||||||
|
const res = await auth.api.getMCPProtectedResource();
|
||||||
|
return new Response(JSON.stringify(res), {
|
||||||
|
status: 200,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Access-Control-Allow-Origin": "*",
|
||||||
|
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
||||||
|
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
||||||
|
"Access-Control-Max-Age": "86400",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user