@meistrari/auth-nuxt 2.0.0 → 2.0.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.json +1 -1
- package/dist/module.mjs +6 -7
- package/dist/runtime/composables/application-auth.d.ts +30 -2
- package/dist/runtime/composables/state.d.ts +86 -5
- package/dist/runtime/middleware/require-auth.d.ts +2 -0
- package/dist/runtime/middleware/require-auth.js +42 -0
- package/dist/runtime/pages/callback.vue +3 -14
- package/dist/runtime/plugins/auth-guard.d.ts +0 -20
- package/dist/runtime/plugins/directives.js +1 -6
- package/dist/runtime/server/utils/require-auth.d.ts +2 -8
- package/dist/runtime/server/utils/require-auth.js +15 -34
- package/dist/runtime/shared.d.ts +2 -1
- package/package.json +2 -2
- package/dist/runtime/server/middleware/application-auth.d.ts +0 -4
- package/dist/runtime/server/middleware/application-auth.js +0 -49
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineNuxtModule, createResolver, addImports, addPlugin, extendPages, addComponent, addServerImportsDir, addServerHandler } from '@nuxt/kit';
|
|
1
|
+
import { defineNuxtModule, createResolver, addImports, addPlugin, extendPages, addComponent, addRouteMiddleware, addServerImportsDir, addServerHandler } from '@nuxt/kit';
|
|
2
2
|
|
|
3
3
|
const module$1 = defineNuxtModule({
|
|
4
4
|
meta: {
|
|
@@ -39,13 +39,12 @@ const module$1 = defineNuxtModule({
|
|
|
39
39
|
});
|
|
40
40
|
addPlugin(resolver.resolve("./runtime/plugins/auth-guard"));
|
|
41
41
|
addPlugin(resolver.resolve("./runtime/plugins/directives"));
|
|
42
|
+
addRouteMiddleware({
|
|
43
|
+
name: "tela-auth",
|
|
44
|
+
path: resolver.resolve("./runtime/middleware/require-auth"),
|
|
45
|
+
global: true
|
|
46
|
+
});
|
|
42
47
|
addServerImportsDir(resolver.resolve("./runtime/server/utils"));
|
|
43
|
-
if (!options.skipServerMiddleware) {
|
|
44
|
-
addServerHandler({
|
|
45
|
-
route: "",
|
|
46
|
-
handler: resolver.resolve("./runtime/server/middleware/application-auth")
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
48
|
return;
|
|
50
49
|
}
|
|
51
50
|
if (!options.skipServerMiddleware) {
|
|
@@ -36,6 +36,34 @@ export declare function useTelaApplicationAuth(): {
|
|
|
36
36
|
login: () => Promise<void>;
|
|
37
37
|
logout: () => Promise<void>;
|
|
38
38
|
initSession: () => Promise<void>;
|
|
39
|
-
user: import("vue").Ref<
|
|
40
|
-
|
|
39
|
+
user: import("vue").Ref<{
|
|
40
|
+
id: string;
|
|
41
|
+
createdAt: Date;
|
|
42
|
+
updatedAt: Date;
|
|
43
|
+
email: string;
|
|
44
|
+
emailVerified: boolean;
|
|
45
|
+
name: string;
|
|
46
|
+
image?: string | null | undefined;
|
|
47
|
+
twoFactorEnabled: boolean | null | undefined;
|
|
48
|
+
banned: boolean | null | undefined;
|
|
49
|
+
role?: string | null | undefined;
|
|
50
|
+
banReason?: string | null | undefined;
|
|
51
|
+
banExpires?: Date | null | undefined;
|
|
52
|
+
lastActiveAt?: Date | null | undefined;
|
|
53
|
+
} | null, {
|
|
54
|
+
id: string;
|
|
55
|
+
createdAt: Date;
|
|
56
|
+
updatedAt: Date;
|
|
57
|
+
email: string;
|
|
58
|
+
emailVerified: boolean;
|
|
59
|
+
name: string;
|
|
60
|
+
image?: string | null | undefined;
|
|
61
|
+
twoFactorEnabled: boolean | null | undefined;
|
|
62
|
+
banned: boolean | null | undefined;
|
|
63
|
+
role?: string | null | undefined;
|
|
64
|
+
banReason?: string | null | undefined;
|
|
65
|
+
banExpires?: Date | null | undefined;
|
|
66
|
+
lastActiveAt?: Date | null | undefined;
|
|
67
|
+
} | null>;
|
|
68
|
+
activeOrganization: import("vue").Ref<Omit<import("@meistrari/auth-core").FullOrganization, "members" | "invitations" | "teams"> | null, Omit<import("@meistrari/auth-core").FullOrganization, "members" | "invitations" | "teams"> | null>;
|
|
41
69
|
};
|
|
@@ -1,20 +1,101 @@
|
|
|
1
|
+
import type { FullOrganization, Member } from '@meistrari/auth-core';
|
|
1
2
|
/**
|
|
2
3
|
* Shared state for session management.
|
|
3
4
|
* This module provides access to session-related state without creating circular dependencies.
|
|
4
5
|
*/
|
|
5
6
|
export declare function useSessionState(): {
|
|
6
|
-
user: import("vue").Ref<
|
|
7
|
-
|
|
7
|
+
user: import("vue").Ref<{
|
|
8
|
+
id: string;
|
|
9
|
+
createdAt: Date;
|
|
10
|
+
updatedAt: Date;
|
|
11
|
+
email: string;
|
|
12
|
+
emailVerified: boolean;
|
|
13
|
+
name: string;
|
|
14
|
+
image?: string | null | undefined;
|
|
15
|
+
twoFactorEnabled: boolean | null | undefined;
|
|
16
|
+
banned: boolean | null | undefined;
|
|
17
|
+
role?: string | null | undefined;
|
|
18
|
+
banReason?: string | null | undefined;
|
|
19
|
+
banExpires?: Date | null | undefined;
|
|
20
|
+
lastActiveAt?: Date | null | undefined;
|
|
21
|
+
} | null, {
|
|
22
|
+
id: string;
|
|
23
|
+
createdAt: Date;
|
|
24
|
+
updatedAt: Date;
|
|
25
|
+
email: string;
|
|
26
|
+
emailVerified: boolean;
|
|
27
|
+
name: string;
|
|
28
|
+
image?: string | null | undefined;
|
|
29
|
+
twoFactorEnabled: boolean | null | undefined;
|
|
30
|
+
banned: boolean | null | undefined;
|
|
31
|
+
role?: string | null | undefined;
|
|
32
|
+
banReason?: string | null | undefined;
|
|
33
|
+
banExpires?: Date | null | undefined;
|
|
34
|
+
lastActiveAt?: Date | null | undefined;
|
|
35
|
+
} | null>;
|
|
36
|
+
session: import("vue").Ref<{
|
|
37
|
+
id: string;
|
|
38
|
+
createdAt: Date;
|
|
39
|
+
updatedAt: Date;
|
|
40
|
+
userId: string;
|
|
41
|
+
expiresAt: Date;
|
|
42
|
+
token: string;
|
|
43
|
+
ipAddress?: string | null | undefined;
|
|
44
|
+
userAgent?: string | null | undefined;
|
|
45
|
+
activeOrganizationId?: string | null | undefined;
|
|
46
|
+
activeTeamId?: string | null | undefined;
|
|
47
|
+
impersonatedBy?: string | null | undefined;
|
|
48
|
+
} | null, {
|
|
49
|
+
id: string;
|
|
50
|
+
createdAt: Date;
|
|
51
|
+
updatedAt: Date;
|
|
52
|
+
userId: string;
|
|
53
|
+
expiresAt: Date;
|
|
54
|
+
token: string;
|
|
55
|
+
ipAddress?: string | null | undefined;
|
|
56
|
+
userAgent?: string | null | undefined;
|
|
57
|
+
activeOrganizationId?: string | null | undefined;
|
|
58
|
+
activeTeamId?: string | null | undefined;
|
|
59
|
+
impersonatedBy?: string | null | undefined;
|
|
60
|
+
} | null>;
|
|
8
61
|
};
|
|
9
62
|
/**
|
|
10
63
|
* Shared state for organization management.
|
|
11
64
|
* This module provides access to organization-related state without creating circular dependencies.
|
|
12
65
|
*/
|
|
13
66
|
export declare function useOrganizationState(): {
|
|
14
|
-
activeOrganization: import("vue").Ref<
|
|
15
|
-
activeMember: import("vue").Ref<
|
|
67
|
+
activeOrganization: import("vue").Ref<FullOrganization | null, FullOrganization | null>;
|
|
68
|
+
activeMember: import("vue").Ref<Member | null, Member | null>;
|
|
16
69
|
};
|
|
17
70
|
export declare function useApplicationSessionState(): {
|
|
18
|
-
user: import("vue").Ref<
|
|
71
|
+
user: import("vue").Ref<{
|
|
72
|
+
id: string;
|
|
73
|
+
createdAt: Date;
|
|
74
|
+
updatedAt: Date;
|
|
75
|
+
email: string;
|
|
76
|
+
emailVerified: boolean;
|
|
77
|
+
name: string;
|
|
78
|
+
image?: string | null | undefined;
|
|
79
|
+
twoFactorEnabled: boolean | null | undefined;
|
|
80
|
+
banned: boolean | null | undefined;
|
|
81
|
+
role?: string | null | undefined;
|
|
82
|
+
banReason?: string | null | undefined;
|
|
83
|
+
banExpires?: Date | null | undefined;
|
|
84
|
+
lastActiveAt?: Date | null | undefined;
|
|
85
|
+
} | null, {
|
|
86
|
+
id: string;
|
|
87
|
+
createdAt: Date;
|
|
88
|
+
updatedAt: Date;
|
|
89
|
+
email: string;
|
|
90
|
+
emailVerified: boolean;
|
|
91
|
+
name: string;
|
|
92
|
+
image?: string | null | undefined;
|
|
93
|
+
twoFactorEnabled: boolean | null | undefined;
|
|
94
|
+
banned: boolean | null | undefined;
|
|
95
|
+
role?: string | null | undefined;
|
|
96
|
+
banReason?: string | null | undefined;
|
|
97
|
+
banExpires?: Date | null | undefined;
|
|
98
|
+
lastActiveAt?: Date | null | undefined;
|
|
99
|
+
} | null>;
|
|
19
100
|
activeOrganization: import("vue").Ref<Omit<FullOrganization, "members" | "invitations" | "teams"> | null, Omit<FullOrganization, "members" | "invitations" | "teams"> | null>;
|
|
20
101
|
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { defineNuxtRouteMiddleware, navigateTo, useCookie, useRuntimeConfig } from "#app";
|
|
2
|
+
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
3
|
+
export default defineNuxtRouteMiddleware(async (to) => {
|
|
4
|
+
const authMeta = to.meta?.auth;
|
|
5
|
+
if (!authMeta || authMeta.required !== true) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const config = useRuntimeConfig();
|
|
9
|
+
const authConfig = config.public.telaAuth;
|
|
10
|
+
const { apiUrl, application } = authConfig;
|
|
11
|
+
const { applicationId, loginPath = "/login", unauthorizedPath = "/unauthorized" } = application ?? {};
|
|
12
|
+
const token = useCookie("tela-access-token");
|
|
13
|
+
if (!token.value) {
|
|
14
|
+
return navigateTo(loginPath);
|
|
15
|
+
}
|
|
16
|
+
if (!applicationId || !apiUrl) {
|
|
17
|
+
console.error("Application ID or API URL is not configured");
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const { payload } = await jwtVerify(
|
|
22
|
+
token.value,
|
|
23
|
+
createRemoteJWKSet(new URL("/.well-known/jwks.json", apiUrl)),
|
|
24
|
+
{
|
|
25
|
+
issuer: apiUrl,
|
|
26
|
+
audience: applicationId,
|
|
27
|
+
algorithms: ["RS256"]
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
const tokenPayload = payload;
|
|
31
|
+
const user = tokenPayload.user;
|
|
32
|
+
if (authMeta.roles && authMeta.roles.length > 0) {
|
|
33
|
+
const userRole = user.role ?? "";
|
|
34
|
+
if (!authMeta.roles.includes(userRole)) {
|
|
35
|
+
return navigateTo(unauthorizedPath);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error("Token validation failed:", error);
|
|
40
|
+
return navigateTo(loginPath);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
@@ -1,22 +1,11 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { navigateTo
|
|
2
|
+
import { navigateTo } from "#app";
|
|
3
3
|
import { onMounted } from "vue";
|
|
4
4
|
import { useTelaApplicationAuth } from "../composables/application-auth";
|
|
5
5
|
const { initSession } = useTelaApplicationAuth();
|
|
6
|
-
const config = useRuntimeConfig();
|
|
7
|
-
const authConfig = config.public.telaAuth;
|
|
8
|
-
const loginPath = authConfig.application?.loginPath ?? "/login";
|
|
9
6
|
onMounted(async () => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
navigateTo("/");
|
|
13
|
-
} catch (error) {
|
|
14
|
-
console.error("Session initialization failed:", error);
|
|
15
|
-
navigateTo({
|
|
16
|
-
path: loginPath,
|
|
17
|
-
query: { error: "session_failed" }
|
|
18
|
-
});
|
|
19
|
-
}
|
|
7
|
+
await initSession();
|
|
8
|
+
navigateTo("/");
|
|
20
9
|
});
|
|
21
10
|
</script>
|
|
22
11
|
|
|
@@ -1,22 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Client-side authentication guard plugin
|
|
3
|
-
*
|
|
4
|
-
* This plugin provides UX-level route protection by checking JWT tokens client-side
|
|
5
|
-
* and redirecting users before they navigate to protected routes. This creates a smooth
|
|
6
|
-
* user experience by avoiding unnecessary page loads.
|
|
7
|
-
*
|
|
8
|
-
* SECURITY NOTE: This is NOT the primary security layer. The client-side JWT decoding
|
|
9
|
-
* is for UX purposes only. Actual cryptographic verification happens server-side in:
|
|
10
|
-
* - application-auth.ts: Server middleware that verifies JWTs for all /api routes
|
|
11
|
-
* - require-auth.ts: Server utility for protecting individual API route handlers
|
|
12
|
-
*
|
|
13
|
-
* An attacker could bypass this client-side check, but they cannot bypass the server-side
|
|
14
|
-
* verification which cryptographically validates the JWT signature using JWKS.
|
|
15
|
-
*
|
|
16
|
-
* This follows a defense-in-depth approach:
|
|
17
|
-
* 1. Client-side (this file): Fast UX-level routing decisions
|
|
18
|
-
* 2. Server middleware: Automatic JWT verification for all API routes
|
|
19
|
-
* 3. Route handlers: Explicit role checks in sensitive endpoints
|
|
20
|
-
*/
|
|
21
1
|
declare const _default: import("#app").Plugin<Record<string, unknown>> & import("#app").ObjectPlugin<Record<string, unknown>>;
|
|
22
2
|
export default _default;
|
|
@@ -23,7 +23,7 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
23
23
|
const isComment = el.nodeType === 8;
|
|
24
24
|
if (shouldRender && isComment) {
|
|
25
25
|
const originalElement = el.__vIfRoleElement;
|
|
26
|
-
if (originalElement
|
|
26
|
+
if (originalElement) {
|
|
27
27
|
el.parentNode?.replaceChild(originalElement, el);
|
|
28
28
|
}
|
|
29
29
|
} else if (!shouldRender && !isComment) {
|
|
@@ -31,11 +31,6 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
31
31
|
el.parentNode?.replaceChild(comment, el);
|
|
32
32
|
comment.__vIfRoleElement = el;
|
|
33
33
|
}
|
|
34
|
-
},
|
|
35
|
-
unmounted(el) {
|
|
36
|
-
if (el.nodeType === 8) {
|
|
37
|
-
delete el.__vIfRoleElement;
|
|
38
|
-
}
|
|
39
34
|
}
|
|
40
35
|
});
|
|
41
36
|
nuxtApp.vueApp.directive("show-role", {
|
|
@@ -2,14 +2,7 @@ import type { EventHandlerRequest } from 'h3';
|
|
|
2
2
|
import type { AuthenticatedH3Event } from '../types/h3.js';
|
|
3
3
|
/**
|
|
4
4
|
* Wraps an event handler to require authentication.
|
|
5
|
-
* Throws 401 if no valid token is present
|
|
6
|
-
*
|
|
7
|
-
* This utility works in two modes:
|
|
8
|
-
* 1. If application-auth middleware has already verified the token, reuses that context
|
|
9
|
-
* 2. If middleware is skipped (skipServerMiddleware: true), performs JWT verification
|
|
10
|
-
*
|
|
11
|
-
* Use this when you need explicit role-based access control on specific API routes,
|
|
12
|
-
* or when you've disabled the global server middleware for performance reasons.
|
|
5
|
+
* Throws 401 if no valid token is present.
|
|
13
6
|
*
|
|
14
7
|
* @example
|
|
15
8
|
* export default requireAuth(async (event) => {
|
|
@@ -19,6 +12,7 @@ import type { AuthenticatedH3Event } from '../types/h3.js';
|
|
|
19
12
|
*
|
|
20
13
|
* @example With roles
|
|
21
14
|
* export default requireAuth(async (event) => {
|
|
15
|
+
* // TODO: Validate roles from token
|
|
22
16
|
* return { data: 'admin only' }
|
|
23
17
|
* }, { roles: ['admin'] })
|
|
24
18
|
*/
|
|
@@ -3,17 +3,6 @@ import { createError, defineEventHandler, getCookie } from "h3";
|
|
|
3
3
|
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
4
4
|
export function requireAuth(handler, options) {
|
|
5
5
|
return defineEventHandler(async (event) => {
|
|
6
|
-
if (event.context.auth?.user && event.context.auth?.token) {
|
|
7
|
-
const user = event.context.auth.user;
|
|
8
|
-
if (options?.roles && !options.roles.includes(user.role ?? "")) {
|
|
9
|
-
throw createError({
|
|
10
|
-
statusCode: 403,
|
|
11
|
-
statusMessage: "Forbidden",
|
|
12
|
-
message: "User is not authorized to access this resource"
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
return handler(event);
|
|
16
|
-
}
|
|
17
6
|
const token = getCookie(event, "tela-access-token");
|
|
18
7
|
const authConfig = useRuntimeConfig(event).public.telaAuth;
|
|
19
8
|
const { apiUrl, application } = authConfig;
|
|
@@ -39,31 +28,23 @@ export function requireAuth(handler, options) {
|
|
|
39
28
|
message: "Authentication required"
|
|
40
29
|
});
|
|
41
30
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (options?.roles && !options.roles.includes(user.role ?? "")) {
|
|
50
|
-
throw createError({
|
|
51
|
-
statusCode: 403,
|
|
52
|
-
statusMessage: "Forbidden",
|
|
53
|
-
message: "User is not authorized to access this resource"
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
event.context.auth = { user: { ...payload.user, email: payload.email }, workspace: payload.workspace, token };
|
|
57
|
-
return handler(event);
|
|
58
|
-
} catch (error) {
|
|
59
|
-
if (error && typeof error === "object" && "statusCode" in error) {
|
|
60
|
-
throw error;
|
|
61
|
-
}
|
|
31
|
+
const payload = await jwtVerify(token, createRemoteJWKSet(new URL("/.well-known/jwks.json", apiUrl)), {
|
|
32
|
+
issuer: apiUrl,
|
|
33
|
+
audience: applicationId,
|
|
34
|
+
algorithms: ["RS256"]
|
|
35
|
+
}).then(({ payload: payload2 }) => payload2);
|
|
36
|
+
const user = payload.user;
|
|
37
|
+
if (options?.roles && !options.roles.includes(user.role ?? "")) {
|
|
62
38
|
throw createError({
|
|
63
|
-
statusCode:
|
|
64
|
-
statusMessage: "
|
|
65
|
-
message: "
|
|
39
|
+
statusCode: 403,
|
|
40
|
+
statusMessage: "Forbidden",
|
|
41
|
+
message: "User is not authorized to access this resource"
|
|
66
42
|
});
|
|
67
43
|
}
|
|
44
|
+
if (!event.context.auth) {
|
|
45
|
+
event.context.auth = { user: { ...payload.user, email: payload.email }, workspace: payload.workspace, token };
|
|
46
|
+
}
|
|
47
|
+
event.context.auth.token = token;
|
|
48
|
+
return handler(event);
|
|
68
49
|
});
|
|
69
50
|
}
|
package/dist/runtime/shared.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import { AuthClient } from '@meistrari/auth-core';
|
|
2
|
+
export declare function createNuxtAuthClient(apiUrl: string, getAuthToken: () => string | null, getRefreshToken?: () => string | null): AuthClient;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meistrari/auth-nuxt",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"build": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxt-module-build build"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@meistrari/auth-core": "
|
|
34
|
+
"@meistrari/auth-core": "1.4.0",
|
|
35
35
|
"jose": "6.1.3"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { AuthenticatedH3Event } from '../types/h3.js';
|
|
2
|
-
export declare function meistrariApplicationAuthMiddleware(callback: (event: AuthenticatedH3Event) => void | Promise<void>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
|
|
3
|
-
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
|
|
4
|
-
export default _default;
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { useRuntimeConfig } from "#build/types/nitro-imports";
|
|
2
|
-
import { defineEventHandler, getCookie } from "h3";
|
|
3
|
-
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
4
|
-
async function setApplicationAuthContext(event) {
|
|
5
|
-
event.context.auth = {
|
|
6
|
-
user: null,
|
|
7
|
-
workspace: null,
|
|
8
|
-
token: null
|
|
9
|
-
};
|
|
10
|
-
const token = getCookie(event, "tela-access-token");
|
|
11
|
-
if (!token) {
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
const authConfig = useRuntimeConfig(event).public.telaAuth;
|
|
15
|
-
const { apiUrl, application } = authConfig;
|
|
16
|
-
const { applicationId } = application ?? {};
|
|
17
|
-
if (!applicationId || !apiUrl) {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
try {
|
|
21
|
-
const payload = await jwtVerify(
|
|
22
|
-
token,
|
|
23
|
-
createRemoteJWKSet(new URL("/.well-known/jwks.json", apiUrl)),
|
|
24
|
-
{
|
|
25
|
-
issuer: apiUrl,
|
|
26
|
-
audience: applicationId,
|
|
27
|
-
algorithms: ["RS256"]
|
|
28
|
-
}
|
|
29
|
-
).then(({ payload: payload2 }) => payload2);
|
|
30
|
-
event.context.auth = {
|
|
31
|
-
user: { ...payload.user, email: payload.email },
|
|
32
|
-
workspace: payload.workspace,
|
|
33
|
-
token
|
|
34
|
-
};
|
|
35
|
-
} catch {
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
export function meistrariApplicationAuthMiddleware(callback) {
|
|
39
|
-
return defineEventHandler(async (event) => {
|
|
40
|
-
await setApplicationAuthContext(event);
|
|
41
|
-
await callback(event);
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
export default defineEventHandler(async (event) => {
|
|
45
|
-
if (!event.path.startsWith("/api")) {
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
await setApplicationAuthContext(event);
|
|
49
|
-
});
|