@meistrari/auth-nuxt 0.2.0 → 1.0.0
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/README.md +294 -145
- package/dist/module.d.mts +1 -3
- package/dist/module.json +3 -3
- package/dist/module.mjs +20 -26
- package/dist/runtime/composables/api-key.d.ts +40 -0
- package/dist/runtime/composables/api-key.js +29 -0
- package/dist/runtime/composables/organization.d.ts +115 -0
- package/dist/runtime/composables/organization.js +164 -0
- package/dist/runtime/composables/session.d.ts +63 -0
- package/dist/runtime/composables/session.js +88 -0
- package/dist/runtime/composables/state.d.ts +22 -0
- package/dist/runtime/composables/state.js +17 -0
- package/dist/runtime/plugin.d.ts +1 -14
- package/dist/runtime/plugin.js +69 -84
- package/dist/runtime/server/middleware/auth.js +11 -16
- package/dist/runtime/server/tsconfig.json +4 -1
- package/dist/runtime/server/types/h3.d.ts +12 -12
- package/dist/runtime/shared.d.ts +1 -0
- package/dist/runtime/shared.js +19 -0
- package/package.json +3 -4
- package/dist/runtime/composable.d.ts +0 -5
- package/dist/runtime/composable.js +0 -29
- package/dist/runtime/server/api/sign-out.d.ts +0 -2
- package/dist/runtime/server/api/sign-out.js +0 -16
- package/dist/runtime/server/middleware/set-cookies.d.ts +0 -2
- package/dist/runtime/server/middleware/set-cookies.js +0 -42
package/dist/runtime/plugin.js
CHANGED
|
@@ -1,105 +1,90 @@
|
|
|
1
|
-
import { defineNuxtPlugin, useCookie,
|
|
1
|
+
import { defineNuxtPlugin, useCookie, useRuntimeConfig, useRequestURL } from "#app";
|
|
2
2
|
import { watch } from "vue";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { useTelaSession } from "./composables/session.js";
|
|
4
|
+
import { createNuxtAuthClient } from "./shared.js";
|
|
5
|
+
import { useRoute, navigateTo } from "#imports";
|
|
5
6
|
export default defineNuxtPlugin({
|
|
6
|
-
name: "
|
|
7
|
-
|
|
7
|
+
name: "tela-auth",
|
|
8
|
+
enforce: "pre",
|
|
9
|
+
env: {
|
|
10
|
+
islands: false
|
|
11
|
+
},
|
|
8
12
|
async setup() {
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
fetchOptions: {
|
|
30
|
-
// on the client side we include credentials
|
|
31
|
-
credentials: "include",
|
|
32
|
-
// on the server side we forward the cookies
|
|
33
|
-
headers,
|
|
34
|
-
onSuccess: (ctx) => {
|
|
35
|
-
const jwt = ctx.response.headers.get("set-auth-jwt");
|
|
36
|
-
if (jwt) {
|
|
37
|
-
token.value = jwt;
|
|
38
|
-
}
|
|
13
|
+
const authConfig = useRuntimeConfig().public.telaAuth;
|
|
14
|
+
const { session, user, getToken } = useTelaSession();
|
|
15
|
+
const tokenCookie = useCookie(authConfig.jwtCookieName);
|
|
16
|
+
tokenCookie.value = null;
|
|
17
|
+
const authClient = createNuxtAuthClient(authConfig.apiUrl, () => tokenCookie.value ?? null);
|
|
18
|
+
const query = useRoute().query;
|
|
19
|
+
const nonce = query.nonce;
|
|
20
|
+
const origin = useRequestURL();
|
|
21
|
+
if (import.meta.server) {
|
|
22
|
+
if (nonce && typeof nonce === "string") {
|
|
23
|
+
if (nonce !== "null") {
|
|
24
|
+
try {
|
|
25
|
+
const payload = await authClient.session.getNoncePayload(nonce);
|
|
26
|
+
tokenCookie.value = payload.token;
|
|
27
|
+
} catch {
|
|
28
|
+
await navigateTo(`${authConfig.apiUrl}/api/auth/handshake?origin=${origin.toString()}`, {
|
|
29
|
+
external: true,
|
|
30
|
+
redirectCode: 302
|
|
31
|
+
});
|
|
32
|
+
return;
|
|
39
33
|
}
|
|
40
34
|
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
} else {
|
|
36
|
+
await navigateTo(`${authConfig.apiUrl}/api/auth/handshake?origin=${origin.toString()}`, {
|
|
37
|
+
external: true,
|
|
38
|
+
redirectCode: 302
|
|
39
|
+
});
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
} else if (import.meta.client && !session.value) {
|
|
43
|
+
const token = await getToken();
|
|
44
|
+
if (token) {
|
|
45
|
+
tokenCookie.value = token;
|
|
44
46
|
}
|
|
45
|
-
return token.value;
|
|
46
47
|
}
|
|
47
48
|
async function initializeSession() {
|
|
48
49
|
if (session.value && user.value)
|
|
49
50
|
return;
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
const { data: sessionData, error: sessionError } = await authClient.getSession(
|
|
53
|
-
{
|
|
54
|
-
fetchOptions: {
|
|
55
|
-
// on the client side we include credentials
|
|
56
|
-
credentials: "include",
|
|
57
|
-
// on the server side we forward the cookies
|
|
58
|
-
headers,
|
|
59
|
-
...config.useJwt && {
|
|
60
|
-
onSuccess: (context) => {
|
|
61
|
-
const jwt = context.response.headers.get("Set-Auth-Jwt");
|
|
62
|
-
if (jwt) {
|
|
63
|
-
token.value = jwt;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
);
|
|
70
|
-
if (sessionError || !sessionData) {
|
|
51
|
+
const sessionData = await authClient.session.getSession();
|
|
52
|
+
if (!sessionData) {
|
|
71
53
|
return;
|
|
72
54
|
}
|
|
73
55
|
user.value = sessionData.user;
|
|
74
56
|
session.value = sessionData.session;
|
|
75
57
|
}
|
|
76
|
-
|
|
58
|
+
if (tokenCookie.value) {
|
|
59
|
+
await initializeSession();
|
|
60
|
+
}
|
|
77
61
|
if (import.meta.client) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
62
|
+
let tokenRefreshInterval = null;
|
|
63
|
+
watch(session, async (newVal) => {
|
|
64
|
+
if (tokenRefreshInterval) {
|
|
65
|
+
clearTimeout(tokenRefreshInterval);
|
|
66
|
+
tokenRefreshInterval = null;
|
|
67
|
+
}
|
|
68
|
+
if (newVal) {
|
|
69
|
+
async function createTokenRefreshInterval() {
|
|
70
|
+
const token = await getToken();
|
|
71
|
+
if (token) {
|
|
72
|
+
tokenCookie.value = token;
|
|
89
73
|
}
|
|
90
|
-
createTokenRefreshInterval
|
|
74
|
+
tokenRefreshInterval = window.setTimeout(createTokenRefreshInterval, 6e4);
|
|
91
75
|
}
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
provide: {
|
|
97
|
-
auth: {
|
|
98
|
-
client: authClient,
|
|
99
|
-
getToken,
|
|
100
|
-
refreshToken
|
|
76
|
+
createTokenRefreshInterval();
|
|
101
77
|
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
78
|
+
}, { immediate: true });
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
hooks: {
|
|
82
|
+
"app:mounted": () => {
|
|
83
|
+
const url = new URL(window.location.href);
|
|
84
|
+
url.searchParams.delete("session");
|
|
85
|
+
url.searchParams.delete("session_data");
|
|
86
|
+
url.searchParams.delete("nonce");
|
|
87
|
+
window.history.replaceState({}, "", url.pathname + url.search + url.hash);
|
|
88
|
+
}
|
|
104
89
|
}
|
|
105
90
|
});
|
|
@@ -1,26 +1,21 @@
|
|
|
1
|
+
import { validateToken, extractTokenPayload } from "@meistrari/auth-core";
|
|
1
2
|
import { defineEventHandler, getCookie } from "h3";
|
|
2
3
|
import { useRuntimeConfig } from "nitropack/runtime/config";
|
|
3
|
-
import { createAuthClient } from "@meistrari/auth-core";
|
|
4
4
|
async function setAuthContext(event) {
|
|
5
5
|
event.context.auth = {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
user: null,
|
|
7
|
+
workspace: null
|
|
8
8
|
};
|
|
9
|
-
const
|
|
10
|
-
|
|
9
|
+
const authConfig = useRuntimeConfig(event).public.telaAuth;
|
|
10
|
+
const tokenCookie = getCookie(event, authConfig.jwtCookieName);
|
|
11
|
+
if (!tokenCookie)
|
|
11
12
|
return;
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
const { data: sessionData, error: sessionError } = await authClient.getSession({
|
|
15
|
-
fetchOptions: {
|
|
16
|
-
headers: event.headers
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
if (sessionError || !sessionData) {
|
|
13
|
+
const isValid = await validateToken(tokenCookie, authConfig.apiUrl);
|
|
14
|
+
if (!isValid)
|
|
20
15
|
return;
|
|
21
|
-
|
|
22
|
-
event.context.auth.
|
|
23
|
-
event.context.auth.
|
|
16
|
+
const payload = extractTokenPayload(tokenCookie);
|
|
17
|
+
event.context.auth.user = { email: payload.email, ...payload.user };
|
|
18
|
+
event.context.auth.workspace = payload.workspace;
|
|
24
19
|
}
|
|
25
20
|
export function meistrariAuthMiddleware(callback) {
|
|
26
21
|
return defineEventHandler(async (event) => {
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { JWTTokenPayload } from '@meistrari/auth-core'
|
|
2
2
|
import type { H3Event, H3EventContext } from 'h3'
|
|
3
3
|
|
|
4
4
|
declare module 'h3' {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
interface H3EventContext {
|
|
6
|
+
auth?: {
|
|
7
|
+
user: { email: string } & JWTTokenPayload['user'] | null
|
|
8
|
+
workspace: JWTTokenPayload['workspace'] | null
|
|
9
|
+
}
|
|
9
10
|
}
|
|
10
|
-
}
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export interface AuthenticatedH3EventContext extends H3EventContext {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
auth: {
|
|
15
|
+
user: { email: string } & JWTTokenPayload['user'] | null
|
|
16
|
+
workspace: JWTTokenPayload['workspace'] | null
|
|
17
|
+
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export interface AuthenticatedH3Event extends H3Event {
|
|
21
|
-
|
|
22
|
-
}
|
|
21
|
+
context: AuthenticatedH3EventContext
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function createNuxtAuthClient(apiUrl: string, getAuthToken: () => string | null): any;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { AuthClient } from "@meistrari/auth-core";
|
|
2
|
+
const version = "__PACKAGE_VERSION__";
|
|
3
|
+
export function createNuxtAuthClient(apiUrl, getAuthToken) {
|
|
4
|
+
const serviceName = typeof process !== "undefined" ? process.env.SERVICE_NAME : "";
|
|
5
|
+
const userAgent = `auth-sdk:nuxt:${version}${serviceName ? `@${serviceName}` : ""}`;
|
|
6
|
+
return new AuthClient(apiUrl, {
|
|
7
|
+
headers: {
|
|
8
|
+
"X-User-Agent": userAgent
|
|
9
|
+
},
|
|
10
|
+
onRequest: (context) => {
|
|
11
|
+
const requestUrl = new URL(context.url);
|
|
12
|
+
const token = getAuthToken();
|
|
13
|
+
const isTokenRequest = requestUrl.pathname.endsWith("/api/auth/token");
|
|
14
|
+
if (token && !isTokenRequest) {
|
|
15
|
+
context.headers.set("Authorization", `Bearer ${token}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meistrari/auth-nuxt",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
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
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"nuxt": "^3.0.0 || ^4.0.0"
|
|
@@ -45,11 +45,10 @@
|
|
|
45
45
|
"@nuxt/test-utils": "3.19.2",
|
|
46
46
|
"@types/node": "latest",
|
|
47
47
|
"changelogen": "0.6.2",
|
|
48
|
-
"eslint": "9.34.0",
|
|
49
48
|
"nuxt": "4.0.3",
|
|
50
49
|
"typescript": "5.9.2",
|
|
51
50
|
"unbuild": "3.6.1",
|
|
52
51
|
"vitest": "3.2.4",
|
|
53
52
|
"vue-tsc": "3.0.6"
|
|
54
53
|
}
|
|
55
|
-
}
|
|
54
|
+
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { useCookie, useState, useRuntimeConfig, useNuxtApp } from "#app";
|
|
2
|
-
export function useMeistrariAuth() {
|
|
3
|
-
const user = useState("user", () => null);
|
|
4
|
-
const session = useState("session", () => null);
|
|
5
|
-
const { useJwt, jwtCookieName, isDevelopment } = useRuntimeConfig().public.auth;
|
|
6
|
-
const { $auth } = useNuxtApp();
|
|
7
|
-
async function signOut(callback) {
|
|
8
|
-
await $auth.client.signOut({
|
|
9
|
-
fetchOptions: {
|
|
10
|
-
onSuccess: async () => {
|
|
11
|
-
if (useJwt) {
|
|
12
|
-
useCookie(jwtCookieName).value = null;
|
|
13
|
-
}
|
|
14
|
-
if (isDevelopment) {
|
|
15
|
-
await $fetch("/api/meistrari-auth/sign-out");
|
|
16
|
-
}
|
|
17
|
-
user.value = null;
|
|
18
|
-
session.value = null;
|
|
19
|
-
callback?.();
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
return {
|
|
25
|
-
user,
|
|
26
|
-
session,
|
|
27
|
-
signOut
|
|
28
|
-
};
|
|
29
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { defineEventHandler, deleteCookie, sendNoContent } from "h3";
|
|
2
|
-
export default defineEventHandler(async (event) => {
|
|
3
|
-
deleteCookie(event, "__Secure-__session", {
|
|
4
|
-
httpOnly: true,
|
|
5
|
-
secure: true,
|
|
6
|
-
sameSite: "lax",
|
|
7
|
-
path: "/"
|
|
8
|
-
});
|
|
9
|
-
deleteCookie(event, "__Secure-__session_data", {
|
|
10
|
-
httpOnly: true,
|
|
11
|
-
secure: true,
|
|
12
|
-
sameSite: "lax",
|
|
13
|
-
path: "/"
|
|
14
|
-
});
|
|
15
|
-
return sendNoContent(event);
|
|
16
|
-
});
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { defineEventHandler, getQuery, setCookie, sendRedirect, getRequestURL } from "h3";
|
|
2
|
-
export default defineEventHandler(async (event) => {
|
|
3
|
-
const query = getQuery(event);
|
|
4
|
-
const hasSessionParam = query.session && typeof query.session === "string";
|
|
5
|
-
const hasSessionDataParam = query.session_data && typeof query.session_data === "string";
|
|
6
|
-
if (hasSessionParam || hasSessionDataParam) {
|
|
7
|
-
if (hasSessionParam) {
|
|
8
|
-
setCookie(event, "__Secure-__session", query.session, {
|
|
9
|
-
httpOnly: true,
|
|
10
|
-
secure: true,
|
|
11
|
-
sameSite: "lax",
|
|
12
|
-
path: "/",
|
|
13
|
-
maxAge: 60 * 60 * 24 * 7
|
|
14
|
-
// 1 week in seconds
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
if (hasSessionDataParam) {
|
|
18
|
-
setCookie(event, "__Secure-__session_data", query.session_data, {
|
|
19
|
-
httpOnly: true,
|
|
20
|
-
secure: true,
|
|
21
|
-
sameSite: "lax",
|
|
22
|
-
path: "/",
|
|
23
|
-
maxAge: 60 * 60 * 24 * 7
|
|
24
|
-
// 1 week in seconds
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
const url = getRequestURL(event);
|
|
28
|
-
const newQuery = new URLSearchParams();
|
|
29
|
-
for (const [key, value] of Object.entries(query)) {
|
|
30
|
-
if (key !== "session" && key !== "session_data" && value !== void 0 && value !== null) {
|
|
31
|
-
if (Array.isArray(value)) {
|
|
32
|
-
value.forEach((v) => newQuery.append(key, String(v)));
|
|
33
|
-
} else {
|
|
34
|
-
newQuery.append(key, String(value));
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
const queryString = newQuery.toString();
|
|
39
|
-
const redirectUrl = `${url.pathname}${queryString ? `?${queryString}` : ""}`;
|
|
40
|
-
return sendRedirect(event, redirectUrl, 302);
|
|
41
|
-
}
|
|
42
|
-
});
|