@wervt/nuxt 0.3.0 → 0.3.1
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/dist/module.js
CHANGED
|
@@ -275,6 +275,10 @@ var module_default = defineNuxtModule({
|
|
|
275
275
|
method: "get",
|
|
276
276
|
handler: resolver.resolve("./runtime/server/user-route")
|
|
277
277
|
});
|
|
278
|
+
if (nitroMajor >= 3) addServerHandler({
|
|
279
|
+
route: "/.well-known/oauth-protected-resource",
|
|
280
|
+
handler: resolver.resolve("./runtime/server/mcp-metadata")
|
|
281
|
+
});
|
|
278
282
|
addPlugin({
|
|
279
283
|
src: resolver.resolve("./runtime/app/plugins/user.client"),
|
|
280
284
|
mode: "client"
|
|
@@ -17,7 +17,9 @@ declare module 'nuxt/schema' {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
export interface McpEndpoint {
|
|
20
|
-
/** This app's
|
|
20
|
+
/** This app's origin, a resource too: tokens for the whole app (native apps) work on `/mcp`. */
|
|
21
|
+
app: string;
|
|
22
|
+
/** This app's `/mcp`, the audience MCP clients' access tokens carry. */
|
|
21
23
|
resource: string;
|
|
22
24
|
/** wervt's login as OAuth issuer, e.g. `https://auth.wervt.app/api/auth`. */
|
|
23
25
|
issuer: string;
|
|
@@ -36,8 +38,8 @@ export declare const CORS: {
|
|
|
36
38
|
'access-control-allow-headers': string;
|
|
37
39
|
'access-control-max-age': string;
|
|
38
40
|
};
|
|
39
|
-
/** RFC 9728: tells
|
|
40
|
-
export declare function protectedResourceMetadata(endpoint: McpEndpoint): {
|
|
41
|
+
/** RFC 9728: tells clients which login issues tokens for `resource` (`/mcp` or the app). */
|
|
42
|
+
export declare function protectedResourceMetadata(endpoint: McpEndpoint, resource?: string): {
|
|
41
43
|
resource: string;
|
|
42
44
|
authorization_servers: string[];
|
|
43
45
|
bearer_methods_supported: string[];
|
|
@@ -12,6 +12,7 @@ function mcpEndpoint(event) {
|
|
|
12
12
|
if (!authUrl) return void 0;
|
|
13
13
|
const appUrl = trimSlash(process.env.WERVT_APP_URL ?? getRequestURL(event).origin);
|
|
14
14
|
return {
|
|
15
|
+
app: appUrl,
|
|
15
16
|
resource: `${appUrl}/mcp`,
|
|
16
17
|
issuer: `${trimSlash(authUrl)}/api/auth`,
|
|
17
18
|
metadataUrl: `${appUrl}/.well-known/oauth-protected-resource/mcp`
|
|
@@ -24,10 +25,10 @@ const CORS = {
|
|
|
24
25
|
"access-control-allow-headers": "*",
|
|
25
26
|
"access-control-max-age": "86400"
|
|
26
27
|
};
|
|
27
|
-
/** RFC 9728: tells
|
|
28
|
-
function protectedResourceMetadata(endpoint) {
|
|
28
|
+
/** RFC 9728: tells clients which login issues tokens for `resource` (`/mcp` or the app). */
|
|
29
|
+
function protectedResourceMetadata(endpoint, resource = endpoint.resource) {
|
|
29
30
|
return {
|
|
30
|
-
resource
|
|
31
|
+
resource,
|
|
31
32
|
authorization_servers: [endpoint.issuer],
|
|
32
33
|
bearer_methods_supported: ["header"],
|
|
33
34
|
scopes_supported: [
|
|
@@ -36,7 +37,7 @@ function protectedResourceMetadata(endpoint) {
|
|
|
36
37
|
"email",
|
|
37
38
|
"offline_access"
|
|
38
39
|
],
|
|
39
|
-
resource_name: new URL(
|
|
40
|
+
resource_name: new URL(resource).hostname.split(".")[0]
|
|
40
41
|
};
|
|
41
42
|
}
|
|
42
43
|
/**
|
|
@@ -69,7 +70,7 @@ async function verifyAccessToken(token, endpoint) {
|
|
|
69
70
|
try {
|
|
70
71
|
const { payload } = await jwtVerify(token, keySet(endpoint.issuer), {
|
|
71
72
|
issuer: endpoint.issuer,
|
|
72
|
-
audience: endpoint.resource,
|
|
73
|
+
audience: [endpoint.resource, endpoint.app],
|
|
73
74
|
requiredClaims: ["exp", "sub"],
|
|
74
75
|
clockTolerance: 5
|
|
75
76
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CORS, mcpEndpoint, protectedResourceMetadata } from "./mcp-auth.js";
|
|
2
|
-
import { defineEventHandler } from "nuxt/server";
|
|
2
|
+
import { defineEventHandler, getRequestURL } from "nuxt/server";
|
|
3
3
|
//#region src/runtime/server/mcp-metadata.ts
|
|
4
4
|
var mcp_metadata_default = defineEventHandler((event) => {
|
|
5
5
|
const endpoint = mcpEndpoint(event);
|
|
@@ -8,7 +8,8 @@ var mcp_metadata_default = defineEventHandler((event) => {
|
|
|
8
8
|
headers: CORS
|
|
9
9
|
});
|
|
10
10
|
if (!endpoint) return Response.json({ error: "No login configured." }, { status: 404 });
|
|
11
|
-
|
|
11
|
+
const mcp = getRequestURL(event).pathname.endsWith("/mcp");
|
|
12
|
+
return Response.json(protectedResourceMetadata(endpoint, mcp ? endpoint.resource : endpoint.app), { headers: CORS });
|
|
12
13
|
});
|
|
13
14
|
//#endregion
|
|
14
15
|
export { mcp_metadata_default as default };
|