@meistrari/auth-nuxt 3.8.0 → 3.9.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/dist/module.json +1 -1
- package/dist/module.mjs +10 -6
- package/dist/runtime/components/tela-role.vue +1 -1
- package/dist/runtime/composables/{application-auth.js → application/auth.js} +4 -4
- package/dist/runtime/composables/application/organization.d.ts +26 -0
- package/dist/runtime/composables/application/organization.js +143 -0
- package/dist/runtime/plugins/application-token-refresh.js +1 -1
- package/dist/runtime/server/routes/auth/api-key-proxy.js +11 -3
- package/dist/runtime/server/routes/auth/organization-proxy.d.ts +2 -0
- package/dist/runtime/server/routes/auth/organization-proxy.js +118 -0
- package/dist/runtime/server/utils/csrf.d.ts +9 -0
- package/dist/runtime/server/utils/csrf.js +19 -0
- package/package.json +2 -2
- package/dist/runtime/server/routes/auth/organizations.d.ts +0 -16
- package/dist/runtime/server/routes/auth/organizations.js +0 -40
- /package/dist/runtime/composables/{application-auth.d.ts → application/auth.d.ts} +0 -0
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -21,7 +21,12 @@ const module$1 = defineNuxtModule({
|
|
|
21
21
|
addImports({
|
|
22
22
|
name: "useTelaApplicationAuth",
|
|
23
23
|
as: "useTelaApplicationAuth",
|
|
24
|
-
from: resolver.resolve("runtime/composables/application
|
|
24
|
+
from: resolver.resolve("runtime/composables/application/auth")
|
|
25
|
+
});
|
|
26
|
+
addImports({
|
|
27
|
+
name: "useTelaOrganization",
|
|
28
|
+
as: "useTelaOrganization",
|
|
29
|
+
from: resolver.resolve("runtime/composables/application/organization")
|
|
25
30
|
});
|
|
26
31
|
addComponent({
|
|
27
32
|
name: "TelaRole",
|
|
@@ -61,11 +66,6 @@ const module$1 = defineNuxtModule({
|
|
|
61
66
|
handler: resolver.resolve("./runtime/server/routes/auth/logout"),
|
|
62
67
|
method: "post"
|
|
63
68
|
});
|
|
64
|
-
addServerHandler({
|
|
65
|
-
route: "/auth/organizations",
|
|
66
|
-
handler: resolver.resolve("./runtime/server/routes/auth/organizations"),
|
|
67
|
-
method: "get"
|
|
68
|
-
});
|
|
69
69
|
addServerHandler({
|
|
70
70
|
route: "/auth/switch-organization",
|
|
71
71
|
handler: resolver.resolve("./runtime/server/routes/auth/switch-organization"),
|
|
@@ -80,6 +80,10 @@ const module$1 = defineNuxtModule({
|
|
|
80
80
|
route: "/api/auth/api-key/**",
|
|
81
81
|
handler: resolver.resolve("./runtime/server/routes/auth/api-key-proxy")
|
|
82
82
|
});
|
|
83
|
+
addServerHandler({
|
|
84
|
+
route: "/api/auth/organization/**",
|
|
85
|
+
handler: resolver.resolve("./runtime/server/routes/auth/organization-proxy")
|
|
86
|
+
});
|
|
83
87
|
addPlugin(resolver.resolve("./runtime/plugins/application-token-refresh"));
|
|
84
88
|
addPlugin(resolver.resolve("./runtime/plugins/auth-guard"));
|
|
85
89
|
addPlugin(resolver.resolve("./runtime/plugins/directives"));
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { navigateTo, useCookie, useRuntimeConfig } from "#app";
|
|
2
2
|
import { AuthorizationFlowError, isTokenExpired, RefreshTokenExpiredError, UserNotLoggedInError } from "@meistrari/auth-core";
|
|
3
|
-
import { useApplicationSessionState } from "
|
|
4
|
-
import { willTokenExpireIn } from "
|
|
3
|
+
import { useApplicationSessionState } from "../state.js";
|
|
4
|
+
import { willTokenExpireIn } from "../../helpers/token.js";
|
|
5
|
+
import { useTelaOrganization } from "./organization.js";
|
|
5
6
|
const FIFTEEN_MINUTES = 60 * 15;
|
|
6
7
|
const ONE_MINUTE = 60 * 1e3;
|
|
7
8
|
export function useTelaApplicationAuth() {
|
|
@@ -73,8 +74,7 @@ export function useTelaApplicationAuth() {
|
|
|
73
74
|
}
|
|
74
75
|
async function getAvailableOrganizations() {
|
|
75
76
|
try {
|
|
76
|
-
|
|
77
|
-
return result.organizations;
|
|
77
|
+
return await useTelaOrganization().listOrganizations();
|
|
78
78
|
} catch (error) {
|
|
79
79
|
console.error("[Auth Orgs] Failed to list organizations:", error);
|
|
80
80
|
throw error;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CreateTeamPayload, FullOrganization, Invitation, InviteUserToOrganizationOptions, ListMembersOptions, Member, RemoveUserFromOrganizationOptions, Team, TeamMember, UpdateMemberRoleOptions, UpdateTeamPayload } from '@meistrari/auth-core';
|
|
2
|
+
import type { Ref } from 'vue';
|
|
3
|
+
export interface UseTelaApplicationOrganizationReturn {
|
|
4
|
+
activeOrganization: Ref<FullOrganization | null>;
|
|
5
|
+
activeMember: Ref<Member | null>;
|
|
6
|
+
getActiveOrganization: () => Promise<FullOrganization | undefined>;
|
|
7
|
+
getAvailableOrganizations: () => Promise<FullOrganization[]>;
|
|
8
|
+
listOrganizations: () => Promise<FullOrganization[]>;
|
|
9
|
+
listMembers: (options?: ListMembersOptions) => Promise<Member[]>;
|
|
10
|
+
getActiveMember: () => Promise<Member>;
|
|
11
|
+
inviteUserToOrganization: (options: InviteUserToOrganizationOptions) => Promise<Invitation>;
|
|
12
|
+
acceptInvitation: (id: string) => Promise<{
|
|
13
|
+
homeUrl: string | null;
|
|
14
|
+
}>;
|
|
15
|
+
cancelInvitation: (id: string) => Promise<void>;
|
|
16
|
+
removeUserFromOrganization: (options: RemoveUserFromOrganizationOptions) => Promise<void>;
|
|
17
|
+
updateMemberRole: (options: UpdateMemberRoleOptions) => Promise<void>;
|
|
18
|
+
createTeam: (payload: CreateTeamPayload) => Promise<Team>;
|
|
19
|
+
updateTeam: (id: string, payload: UpdateTeamPayload) => Promise<Team>;
|
|
20
|
+
deleteTeam: (id: string) => Promise<void>;
|
|
21
|
+
listTeams: () => Promise<Team[]>;
|
|
22
|
+
listTeamMembers: (id: string) => Promise<TeamMember[]>;
|
|
23
|
+
addTeamMember: (teamId: string, userId: string) => Promise<TeamMember>;
|
|
24
|
+
removeTeamMember: (teamId: string, userId: string) => Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
export declare function useTelaOrganization(): UseTelaApplicationOrganizationReturn;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { useCookie, useRequestURL } from "#app";
|
|
2
|
+
import { createNuxtAuthClient } from "../../shared.js";
|
|
3
|
+
import { useApplicationSessionState, useOrganizationState } from "../state.js";
|
|
4
|
+
export function useTelaOrganization() {
|
|
5
|
+
const { activeOrganization } = useApplicationSessionState();
|
|
6
|
+
const { activeMember } = useOrganizationState();
|
|
7
|
+
const requestUrl = useRequestURL();
|
|
8
|
+
const accessToken = useCookie("tela-access-token");
|
|
9
|
+
const authClient = createNuxtAuthClient(requestUrl.origin, () => accessToken.value ?? null);
|
|
10
|
+
async function getActiveOrganization() {
|
|
11
|
+
if (!activeOrganization.value?.id) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const organization = await authClient.organization.getOrganization(activeOrganization.value.id);
|
|
15
|
+
activeOrganization.value = organization;
|
|
16
|
+
return organization;
|
|
17
|
+
}
|
|
18
|
+
async function getAvailableOrganizations() {
|
|
19
|
+
return await listOrganizations();
|
|
20
|
+
}
|
|
21
|
+
async function listOrganizations() {
|
|
22
|
+
return await authClient.organization.listOrganizations();
|
|
23
|
+
}
|
|
24
|
+
async function listMembers(options) {
|
|
25
|
+
return await authClient.organization.listMembers(options);
|
|
26
|
+
}
|
|
27
|
+
async function getActiveMember() {
|
|
28
|
+
const member = await authClient.organization.getActiveMember();
|
|
29
|
+
activeMember.value = member;
|
|
30
|
+
return member;
|
|
31
|
+
}
|
|
32
|
+
async function inviteUserToOrganization(options) {
|
|
33
|
+
const invitation = await authClient.organization.inviteUserToOrganization(options);
|
|
34
|
+
if (activeOrganization.value) {
|
|
35
|
+
activeOrganization.value = {
|
|
36
|
+
...activeOrganization.value,
|
|
37
|
+
invitations: [...activeOrganization.value.invitations ?? [], invitation]
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return invitation;
|
|
41
|
+
}
|
|
42
|
+
async function acceptInvitation(id) {
|
|
43
|
+
const { homeUrl } = await authClient.organization.acceptInvitation(id);
|
|
44
|
+
const members = await authClient.organization.listMembers();
|
|
45
|
+
if (activeOrganization.value) {
|
|
46
|
+
activeOrganization.value = {
|
|
47
|
+
...activeOrganization.value,
|
|
48
|
+
members
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return { homeUrl };
|
|
52
|
+
}
|
|
53
|
+
async function cancelInvitation(id) {
|
|
54
|
+
await authClient.organization.cancelInvitation(id);
|
|
55
|
+
if (activeOrganization.value) {
|
|
56
|
+
activeOrganization.value = {
|
|
57
|
+
...activeOrganization.value,
|
|
58
|
+
invitations: activeOrganization.value.invitations?.filter((invitation) => invitation.id !== id) ?? []
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async function removeUserFromOrganization(options) {
|
|
63
|
+
await authClient.organization.removeUserFromOrganization(options);
|
|
64
|
+
if (activeOrganization.value) {
|
|
65
|
+
activeOrganization.value = {
|
|
66
|
+
...activeOrganization.value,
|
|
67
|
+
members: activeOrganization.value.members?.filter((member) => member.id !== options.memberId) ?? []
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async function updateMemberRole(options) {
|
|
72
|
+
await authClient.organization.updateMemberRole(options);
|
|
73
|
+
const members = await authClient.organization.listMembers();
|
|
74
|
+
if (activeOrganization.value) {
|
|
75
|
+
activeOrganization.value = {
|
|
76
|
+
...activeOrganization.value,
|
|
77
|
+
members
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async function createTeam(payload) {
|
|
82
|
+
const team = await authClient.organization.createTeam(payload);
|
|
83
|
+
if (activeOrganization.value) {
|
|
84
|
+
activeOrganization.value = {
|
|
85
|
+
...activeOrganization.value,
|
|
86
|
+
teams: [...activeOrganization.value.teams ?? [], team]
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return team;
|
|
90
|
+
}
|
|
91
|
+
async function updateTeam(id, payload) {
|
|
92
|
+
const updatedTeam = await authClient.organization.updateTeam(id, payload);
|
|
93
|
+
if (activeOrganization.value) {
|
|
94
|
+
activeOrganization.value = {
|
|
95
|
+
...activeOrganization.value,
|
|
96
|
+
teams: activeOrganization.value.teams?.map((team) => team.id === id ? updatedTeam : team) ?? []
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return updatedTeam;
|
|
100
|
+
}
|
|
101
|
+
async function deleteTeam(id) {
|
|
102
|
+
await authClient.organization.deleteTeam(id);
|
|
103
|
+
if (activeOrganization.value) {
|
|
104
|
+
activeOrganization.value = {
|
|
105
|
+
...activeOrganization.value,
|
|
106
|
+
teams: activeOrganization.value.teams?.filter((team) => team.id !== id) ?? []
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async function listTeams() {
|
|
111
|
+
return await authClient.organization.listTeams();
|
|
112
|
+
}
|
|
113
|
+
async function listTeamMembers(id) {
|
|
114
|
+
return await authClient.organization.listTeamMembers(id);
|
|
115
|
+
}
|
|
116
|
+
async function addTeamMember(teamId, userId) {
|
|
117
|
+
return await authClient.organization.addTeamMember(teamId, userId);
|
|
118
|
+
}
|
|
119
|
+
async function removeTeamMember(teamId, userId) {
|
|
120
|
+
await authClient.organization.removeTeamMember(teamId, userId);
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
activeOrganization,
|
|
124
|
+
activeMember,
|
|
125
|
+
getActiveOrganization,
|
|
126
|
+
getAvailableOrganizations,
|
|
127
|
+
listOrganizations,
|
|
128
|
+
listMembers,
|
|
129
|
+
getActiveMember,
|
|
130
|
+
inviteUserToOrganization,
|
|
131
|
+
acceptInvitation,
|
|
132
|
+
cancelInvitation,
|
|
133
|
+
removeUserFromOrganization,
|
|
134
|
+
updateMemberRole,
|
|
135
|
+
createTeam,
|
|
136
|
+
updateTeam,
|
|
137
|
+
deleteTeam,
|
|
138
|
+
listTeams,
|
|
139
|
+
listTeamMembers,
|
|
140
|
+
addTeamMember,
|
|
141
|
+
removeTeamMember
|
|
142
|
+
};
|
|
143
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineNuxtPlugin, navigateTo, useCookie, useRoute, useRuntimeConfig } from "#app";
|
|
2
2
|
import { isTokenExpired } from "@meistrari/auth-core";
|
|
3
|
-
import { useTelaApplicationAuth } from "../composables/application
|
|
3
|
+
import { useTelaApplicationAuth } from "../composables/application/auth.js";
|
|
4
4
|
import { useApplicationSessionState } from "../composables/state.js";
|
|
5
5
|
import { createNuxtAuthClient } from "../shared.js";
|
|
6
6
|
import { parseTokenExpiry } from "../helpers/token.js";
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
setResponseHeader,
|
|
9
9
|
setResponseStatus
|
|
10
10
|
} from "h3";
|
|
11
|
+
import { shouldRejectMutationForCsrf } from "../../utils/csrf.js";
|
|
11
12
|
const ALLOWED_REQUEST_HEADERS = /* @__PURE__ */ new Set([
|
|
12
13
|
"accept",
|
|
13
14
|
"content-type"
|
|
@@ -34,7 +35,9 @@ export default defineEventHandler(async (event) => {
|
|
|
34
35
|
const authConfig = useRuntimeConfig(event).public.telaAuth;
|
|
35
36
|
const requestUrl = getRequestURL(event);
|
|
36
37
|
const requestHeaders = getHeaders(event);
|
|
37
|
-
const
|
|
38
|
+
const cookieAccessToken = getCookie(event, "tela-access-token");
|
|
39
|
+
const bearerAccessToken = getBearerToken(requestHeaders.authorization);
|
|
40
|
+
const accessToken = cookieAccessToken ?? bearerAccessToken;
|
|
38
41
|
const allowedMethods = ALLOWED_API_KEY_ROUTES.get(requestUrl.pathname);
|
|
39
42
|
if (!authConfig.application?.enabled) {
|
|
40
43
|
throw createError({
|
|
@@ -61,8 +64,13 @@ export default defineEventHandler(async (event) => {
|
|
|
61
64
|
statusMessage: "Method Not Allowed"
|
|
62
65
|
});
|
|
63
66
|
}
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
if (shouldRejectMutationForCsrf({
|
|
68
|
+
hasBearerToken: Boolean(bearerAccessToken),
|
|
69
|
+
hasCookieToken: Boolean(cookieAccessToken),
|
|
70
|
+
method: event.method,
|
|
71
|
+
origin: requestHeaders.origin,
|
|
72
|
+
requestOrigin: requestUrl.origin
|
|
73
|
+
})) {
|
|
66
74
|
throw createError({
|
|
67
75
|
statusCode: 403,
|
|
68
76
|
statusMessage: "Forbidden"
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { createError, useRuntimeConfig } from "#imports";
|
|
2
|
+
import {
|
|
3
|
+
defineEventHandler,
|
|
4
|
+
getCookie,
|
|
5
|
+
getHeaders,
|
|
6
|
+
getRequestURL,
|
|
7
|
+
readRawBody,
|
|
8
|
+
setResponseHeader,
|
|
9
|
+
setResponseStatus
|
|
10
|
+
} from "h3";
|
|
11
|
+
import { shouldRejectMutationForCsrf } from "../../utils/csrf.js";
|
|
12
|
+
const ALLOWED_REQUEST_HEADERS = /* @__PURE__ */ new Set([
|
|
13
|
+
"accept",
|
|
14
|
+
"content-type"
|
|
15
|
+
]);
|
|
16
|
+
const ALLOWED_RESPONSE_HEADERS = /* @__PURE__ */ new Set([
|
|
17
|
+
"cache-control",
|
|
18
|
+
"content-type"
|
|
19
|
+
]);
|
|
20
|
+
const ALLOWED_ORGANIZATION_ROUTES = /* @__PURE__ */ new Map([
|
|
21
|
+
["/api/auth/organization/get-full-organization", /* @__PURE__ */ new Set(["GET"])],
|
|
22
|
+
["/api/auth/organization/list", /* @__PURE__ */ new Set(["GET"])],
|
|
23
|
+
["/api/auth/organization/invite-member", /* @__PURE__ */ new Set(["POST"])],
|
|
24
|
+
["/api/auth/organization/cancel-invitation", /* @__PURE__ */ new Set(["POST"])],
|
|
25
|
+
["/api/auth/organization/accept-invitation", /* @__PURE__ */ new Set(["POST"])],
|
|
26
|
+
["/api/auth/organization/get-invitation", /* @__PURE__ */ new Set(["GET"])],
|
|
27
|
+
["/api/auth/organization/reject-invitation", /* @__PURE__ */ new Set(["POST"])],
|
|
28
|
+
["/api/auth/organization/list-invitations", /* @__PURE__ */ new Set(["GET"])],
|
|
29
|
+
["/api/auth/organization/get-active-member", /* @__PURE__ */ new Set(["GET"])],
|
|
30
|
+
["/api/auth/organization/remove-member", /* @__PURE__ */ new Set(["POST"])],
|
|
31
|
+
["/api/auth/organization/update-member-role", /* @__PURE__ */ new Set(["POST"])],
|
|
32
|
+
["/api/auth/organization/list-user-invitations", /* @__PURE__ */ new Set(["GET"])],
|
|
33
|
+
["/api/auth/organization/list-members", /* @__PURE__ */ new Set(["GET"])],
|
|
34
|
+
["/api/auth/organization/get-active-member-role", /* @__PURE__ */ new Set(["GET"])],
|
|
35
|
+
["/api/auth/organization/create-team", /* @__PURE__ */ new Set(["POST"])],
|
|
36
|
+
["/api/auth/organization/list-teams", /* @__PURE__ */ new Set(["GET"])],
|
|
37
|
+
["/api/auth/organization/remove-team", /* @__PURE__ */ new Set(["POST"])],
|
|
38
|
+
["/api/auth/organization/update-team", /* @__PURE__ */ new Set(["POST"])],
|
|
39
|
+
["/api/auth/organization/list-user-teams", /* @__PURE__ */ new Set(["GET"])],
|
|
40
|
+
["/api/auth/organization/list-team-members", /* @__PURE__ */ new Set(["GET"])],
|
|
41
|
+
["/api/auth/organization/add-team-member", /* @__PURE__ */ new Set(["POST"])],
|
|
42
|
+
["/api/auth/organization/remove-team-member", /* @__PURE__ */ new Set(["POST"])]
|
|
43
|
+
]);
|
|
44
|
+
function getBearerToken(authorization) {
|
|
45
|
+
const value = Array.isArray(authorization) ? authorization[0] : authorization;
|
|
46
|
+
if (!value?.toLowerCase().startsWith("bearer ")) {
|
|
47
|
+
return void 0;
|
|
48
|
+
}
|
|
49
|
+
return value.slice("bearer ".length).trimStart() || void 0;
|
|
50
|
+
}
|
|
51
|
+
export default defineEventHandler(async (event) => {
|
|
52
|
+
const authConfig = useRuntimeConfig(event).public.telaAuth;
|
|
53
|
+
const requestUrl = getRequestURL(event);
|
|
54
|
+
const requestHeaders = getHeaders(event);
|
|
55
|
+
const cookieAccessToken = getCookie(event, "tela-access-token");
|
|
56
|
+
const bearerAccessToken = getBearerToken(requestHeaders.authorization);
|
|
57
|
+
const accessToken = cookieAccessToken ?? bearerAccessToken;
|
|
58
|
+
const allowedMethods = ALLOWED_ORGANIZATION_ROUTES.get(requestUrl.pathname);
|
|
59
|
+
if (!authConfig.application?.enabled) {
|
|
60
|
+
throw createError({
|
|
61
|
+
statusCode: 404,
|
|
62
|
+
statusMessage: "Not Found"
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (!accessToken) {
|
|
66
|
+
throw createError({
|
|
67
|
+
statusCode: 401,
|
|
68
|
+
statusMessage: "Unauthorized",
|
|
69
|
+
message: "No access token found"
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
if (!allowedMethods) {
|
|
73
|
+
throw createError({
|
|
74
|
+
statusCode: 404,
|
|
75
|
+
statusMessage: "Not Found"
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
if (!allowedMethods.has(event.method)) {
|
|
79
|
+
throw createError({
|
|
80
|
+
statusCode: 405,
|
|
81
|
+
statusMessage: "Method Not Allowed"
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
if (shouldRejectMutationForCsrf({
|
|
85
|
+
hasBearerToken: Boolean(bearerAccessToken),
|
|
86
|
+
hasCookieToken: Boolean(cookieAccessToken),
|
|
87
|
+
method: event.method,
|
|
88
|
+
origin: requestHeaders.origin,
|
|
89
|
+
requestOrigin: requestUrl.origin
|
|
90
|
+
})) {
|
|
91
|
+
throw createError({
|
|
92
|
+
statusCode: 403,
|
|
93
|
+
statusMessage: "Forbidden"
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
const targetUrl = new URL(requestUrl.pathname + requestUrl.search, authConfig.apiUrl);
|
|
97
|
+
const headers = new Headers();
|
|
98
|
+
for (const [name, value] of Object.entries(requestHeaders)) {
|
|
99
|
+
if (value && ALLOWED_REQUEST_HEADERS.has(name.toLowerCase())) {
|
|
100
|
+
headers.set(name, Array.isArray(value) ? value.join(", ") : value);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
104
|
+
const method = event.method;
|
|
105
|
+
const body = method === "GET" || method === "HEAD" ? void 0 : await readRawBody(event);
|
|
106
|
+
const response = await fetch(targetUrl, {
|
|
107
|
+
body,
|
|
108
|
+
headers,
|
|
109
|
+
method
|
|
110
|
+
});
|
|
111
|
+
setResponseStatus(event, response.status, response.statusText);
|
|
112
|
+
for (const [name, value] of response.headers) {
|
|
113
|
+
if (ALLOWED_RESPONSE_HEADERS.has(name.toLowerCase())) {
|
|
114
|
+
setResponseHeader(event, name, value);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return await response.text();
|
|
118
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type CsrfMutationOptions = {
|
|
2
|
+
hasBearerToken: boolean;
|
|
3
|
+
hasCookieToken: boolean;
|
|
4
|
+
method: string;
|
|
5
|
+
origin: string | string[] | undefined;
|
|
6
|
+
requestOrigin: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function shouldRejectMutationForCsrf({ hasBearerToken, hasCookieToken, method, origin, requestOrigin, }: CsrfMutationOptions): boolean;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
function getHeaderValue(value) {
|
|
2
|
+
return Array.isArray(value) ? value[0] : value;
|
|
3
|
+
}
|
|
4
|
+
export function shouldRejectMutationForCsrf({
|
|
5
|
+
hasBearerToken,
|
|
6
|
+
hasCookieToken,
|
|
7
|
+
method,
|
|
8
|
+
origin,
|
|
9
|
+
requestOrigin
|
|
10
|
+
}) {
|
|
11
|
+
if (method === "GET") {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
const requestOriginHeader = getHeaderValue(origin);
|
|
15
|
+
if (requestOriginHeader) {
|
|
16
|
+
return requestOriginHeader !== requestOrigin;
|
|
17
|
+
}
|
|
18
|
+
return hasCookieToken && !hasBearerToken;
|
|
19
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meistrari/auth-nuxt",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"docs": "nuxt-module-build prepare && typedoc"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@meistrari/auth-core": "
|
|
39
|
+
"@meistrari/auth-core": "1.20.0",
|
|
40
40
|
"jose": "6.1.3"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Server route handler for listing available organizations
|
|
3
|
-
*
|
|
4
|
-
* This route:
|
|
5
|
-
* 1. Retrieves the access token from the cookie
|
|
6
|
-
* 2. Calls the auth API to get the list of organizations the user can switch to
|
|
7
|
-
* 3. Returns the organizations data
|
|
8
|
-
*
|
|
9
|
-
* Returns only organizations that are entitled to the application and where
|
|
10
|
-
* the entitlement's access rules permit the current user.
|
|
11
|
-
*/
|
|
12
|
-
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{
|
|
13
|
-
success: boolean;
|
|
14
|
-
organizations: import("@meistrari/auth-core").FullOrganization[];
|
|
15
|
-
}>>;
|
|
16
|
-
export default _default;
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { createError, useRuntimeConfig } from "#imports";
|
|
2
|
-
import { defineEventHandler, getCookie } from "h3";
|
|
3
|
-
import { createNuxtAuthClient } from "../../../shared.js";
|
|
4
|
-
export default defineEventHandler(async (event) => {
|
|
5
|
-
const config = useRuntimeConfig();
|
|
6
|
-
const authConfig = config.public.telaAuth;
|
|
7
|
-
const accessToken = getCookie(event, "tela-access-token");
|
|
8
|
-
if (!accessToken) {
|
|
9
|
-
throw createError({
|
|
10
|
-
statusCode: 401,
|
|
11
|
-
statusMessage: "Unauthorized",
|
|
12
|
-
message: "No access token found"
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
if (!authConfig.application?.applicationId) {
|
|
16
|
-
throw createError({
|
|
17
|
-
statusCode: 500,
|
|
18
|
-
statusMessage: "Internal Server Error",
|
|
19
|
-
message: "Application ID is not configured"
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
try {
|
|
23
|
-
const authClient = createNuxtAuthClient(
|
|
24
|
-
authConfig.apiUrl,
|
|
25
|
-
() => accessToken
|
|
26
|
-
);
|
|
27
|
-
const { organizations } = await authClient.application.listCandidateOrganizations(authConfig.application.applicationId);
|
|
28
|
-
return {
|
|
29
|
-
success: true,
|
|
30
|
-
organizations
|
|
31
|
-
};
|
|
32
|
-
} catch (error) {
|
|
33
|
-
console.error("[Auth Orgs] Failed to list organizations:", error);
|
|
34
|
-
throw createError({
|
|
35
|
-
statusCode: 500,
|
|
36
|
-
statusMessage: "Internal Server Error",
|
|
37
|
-
message: "Failed to list organizations"
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
});
|
|
File without changes
|