@thunderid/nuxt 0.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/LICENSE +201 -0
- package/dist/module.d.mts +46 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +216 -0
- package/dist/runtime/components/ThunderIDRoot.d.ts +52 -0
- package/dist/runtime/components/ThunderIDRoot.js +160 -0
- package/dist/runtime/components/actions/SignInButton.d.ts +37 -0
- package/dist/runtime/components/actions/SignInButton.js +51 -0
- package/dist/runtime/components/actions/SignOutButton.d.ts +34 -0
- package/dist/runtime/components/actions/SignOutButton.js +43 -0
- package/dist/runtime/components/actions/SignUpButton.d.ts +33 -0
- package/dist/runtime/components/actions/SignUpButton.js +48 -0
- package/dist/runtime/components/auth/Callback.d.ts +43 -0
- package/dist/runtime/components/auth/Callback.js +93 -0
- package/dist/runtime/components/auth/SignIn.d.ts +38 -0
- package/dist/runtime/components/auth/SignIn.js +60 -0
- package/dist/runtime/components/auth/SignUp.d.ts +40 -0
- package/dist/runtime/components/auth/SignUp.js +79 -0
- package/dist/runtime/components/control/Loading.d.ts +36 -0
- package/dist/runtime/components/control/Loading.js +17 -0
- package/dist/runtime/components/control/SignedIn.d.ts +38 -0
- package/dist/runtime/components/control/SignedIn.js +17 -0
- package/dist/runtime/components/control/SignedOut.d.ts +37 -0
- package/dist/runtime/components/control/SignedOut.js +17 -0
- package/dist/runtime/components/organization/CreateOrganization.d.ts +32 -0
- package/dist/runtime/components/organization/CreateOrganization.js +29 -0
- package/dist/runtime/components/organization/Organization.d.ts +39 -0
- package/dist/runtime/components/organization/Organization.js +17 -0
- package/dist/runtime/components/organization/OrganizationList.d.ts +34 -0
- package/dist/runtime/components/organization/OrganizationList.js +30 -0
- package/dist/runtime/components/organization/OrganizationProfile.d.ts +32 -0
- package/dist/runtime/components/organization/OrganizationProfile.js +32 -0
- package/dist/runtime/components/organization/OrganizationSwitcher.d.ts +36 -0
- package/dist/runtime/components/organization/OrganizationSwitcher.js +26 -0
- package/dist/runtime/components/user/User.d.ts +38 -0
- package/dist/runtime/components/user/User.js +17 -0
- package/dist/runtime/components/user/UserDropdown.d.ts +38 -0
- package/dist/runtime/components/user/UserDropdown.js +45 -0
- package/dist/runtime/components/user/UserProfile.d.ts +35 -0
- package/dist/runtime/components/user/UserProfile.js +35 -0
- package/dist/runtime/composables/useThunderID.d.ts +38 -0
- package/dist/runtime/composables/useThunderID.js +73 -0
- package/dist/runtime/errors/error-codes.d.ts +40 -0
- package/dist/runtime/errors/error-codes.js +19 -0
- package/dist/runtime/errors/index.d.ts +19 -0
- package/dist/runtime/errors/index.js +2 -0
- package/dist/runtime/errors/thunderid-error.d.ts +47 -0
- package/dist/runtime/errors/thunderid-error.js +15 -0
- package/dist/runtime/middleware/auth.d.ts +35 -0
- package/dist/runtime/middleware/auth.js +2 -0
- package/dist/runtime/middleware/defineThunderIDMiddleware.d.ts +53 -0
- package/dist/runtime/middleware/defineThunderIDMiddleware.js +24 -0
- package/dist/runtime/plugins/thunderid.d.ts +39 -0
- package/dist/runtime/plugins/thunderid.js +128 -0
- package/dist/runtime/server/ThunderIDNuxtClient.d.ts +186 -0
- package/dist/runtime/server/ThunderIDNuxtClient.js +384 -0
- package/dist/runtime/server/index.d.ts +33 -0
- package/dist/runtime/server/index.js +3 -0
- package/dist/runtime/server/plugins/thunderid-ssr.d.ts +40 -0
- package/dist/runtime/server/plugins/thunderid-ssr.js +135 -0
- package/dist/runtime/server/routes/auth/branding/branding.get.d.ts +31 -0
- package/dist/runtime/server/routes/auth/branding/branding.get.js +40 -0
- package/dist/runtime/server/routes/auth/organizations/current.get.d.ts +29 -0
- package/dist/runtime/server/routes/auth/organizations/current.get.js +24 -0
- package/dist/runtime/server/routes/auth/organizations/id.get.d.ts +28 -0
- package/dist/runtime/server/routes/auth/organizations/id.get.js +28 -0
- package/dist/runtime/server/routes/auth/organizations/index.get.d.ts +28 -0
- package/dist/runtime/server/routes/auth/organizations/index.get.js +24 -0
- package/dist/runtime/server/routes/auth/organizations/index.post.d.ts +30 -0
- package/dist/runtime/server/routes/auth/organizations/index.post.js +30 -0
- package/dist/runtime/server/routes/auth/organizations/me.get.d.ts +28 -0
- package/dist/runtime/server/routes/auth/organizations/me.get.js +24 -0
- package/dist/runtime/server/routes/auth/organizations/switch.post.d.ts +32 -0
- package/dist/runtime/server/routes/auth/organizations/switch.post.js +49 -0
- package/dist/runtime/server/routes/auth/session/callback.get.d.ts +27 -0
- package/dist/runtime/server/routes/auth/session/callback.get.js +91 -0
- package/dist/runtime/server/routes/auth/session/callback.post.d.ts +48 -0
- package/dist/runtime/server/routes/auth/session/callback.post.js +53 -0
- package/dist/runtime/server/routes/auth/session/session.get.d.ts +26 -0
- package/dist/runtime/server/routes/auth/session/session.get.js +22 -0
- package/dist/runtime/server/routes/auth/session/signin.get.d.ts +29 -0
- package/dist/runtime/server/routes/auth/session/signin.get.js +37 -0
- package/dist/runtime/server/routes/auth/session/signin.post.d.ts +37 -0
- package/dist/runtime/server/routes/auth/session/signin.post.js +102 -0
- package/dist/runtime/server/routes/auth/session/signout.post.d.ts +31 -0
- package/dist/runtime/server/routes/auth/session/signout.post.js +38 -0
- package/dist/runtime/server/routes/auth/session/signup.post.d.ts +36 -0
- package/dist/runtime/server/routes/auth/session/signup.post.js +30 -0
- package/dist/runtime/server/routes/auth/session/token.get.d.ts +29 -0
- package/dist/runtime/server/routes/auth/session/token.get.js +6 -0
- package/dist/runtime/server/routes/auth/user/profile.get.d.ts +29 -0
- package/dist/runtime/server/routes/auth/user/profile.get.js +24 -0
- package/dist/runtime/server/routes/auth/user/profile.patch.d.ts +35 -0
- package/dist/runtime/server/routes/auth/user/profile.patch.js +41 -0
- package/dist/runtime/server/routes/auth/user/user.get.d.ts +25 -0
- package/dist/runtime/server/routes/auth/user/user.get.js +21 -0
- package/dist/runtime/server/utils/event-context.d.ts +49 -0
- package/dist/runtime/server/utils/event-context.js +3 -0
- package/dist/runtime/server/utils/serverSession.d.ts +65 -0
- package/dist/runtime/server/utils/serverSession.js +44 -0
- package/dist/runtime/server/utils/session.d.ts +85 -0
- package/dist/runtime/server/utils/session.js +106 -0
- package/dist/runtime/server/utils/token-refresh.d.ts +42 -0
- package/dist/runtime/server/utils/token-refresh.js +65 -0
- package/dist/runtime/types.d.ts +161 -0
- package/dist/runtime/types.js +0 -0
- package/dist/runtime/utils/createRouteMatcher.d.ts +40 -0
- package/dist/runtime/utils/createRouteMatcher.js +7 -0
- package/dist/runtime/utils/index.d.ts +30 -0
- package/dist/runtime/utils/index.js +1 -0
- package/dist/runtime/utils/log.d.ts +44 -0
- package/dist/runtime/utils/log.js +25 -0
- package/dist/runtime/utils/url-validation.d.ts +49 -0
- package/dist/runtime/utils/url-validation.js +38 -0
- package/dist/types.d.mts +7 -0
- package/package.json +101 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
|
|
3
|
+
*
|
|
4
|
+
* WSO2 LLC. licenses this file to you under the Apache License,
|
|
5
|
+
* Version 2.0 (the "License"); you may not use this file except
|
|
6
|
+
* in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing,
|
|
12
|
+
* software distributed under the License is distributed on an
|
|
13
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
* KIND, either express or implied. See the License for the
|
|
15
|
+
* specific language governing permissions and limitations
|
|
16
|
+
* under the License.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* @thunderid/nuxt/server
|
|
20
|
+
*
|
|
21
|
+
* Public server-only barrel. Import from this subpath to access
|
|
22
|
+
* server utilities without bundling them into the client.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { useServerSession, requireServerSession } from '@thunderid/nuxt/server';
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export { useServerSession, requireServerSession } from './utils/serverSession.js';
|
|
30
|
+
export { getValidAccessToken } from './utils/token-refresh.js';
|
|
31
|
+
export { getThunderIDContext } from './utils/event-context.js';
|
|
32
|
+
export type { ThunderIDEventContext } from './utils/event-context.js';
|
|
33
|
+
export type { ThunderIDSessionPayload, ThunderIDNuxtConfig } from '../types.js';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
|
|
3
|
+
*
|
|
4
|
+
* WSO2 LLC. licenses this file to you under the Apache License,
|
|
5
|
+
* Version 2.0 (the "License"); you may not use this file except
|
|
6
|
+
* in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing,
|
|
12
|
+
* software distributed under the License is distributed on an
|
|
13
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
* KIND, either express or implied. See the License for the
|
|
15
|
+
* specific language governing permissions and limitations
|
|
16
|
+
* under the License.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Nitro server plugin — the Nuxt equivalent of `ThunderIDServerProvider` in the
|
|
20
|
+
* Next.js SDK.
|
|
21
|
+
*
|
|
22
|
+
* On every page request it:
|
|
23
|
+
* 1. Initialises the singleton {@link ThunderIDNuxtClient} once (idempotent).
|
|
24
|
+
* 2. Verifies the JWT session cookie → resolves `isSignedIn`.
|
|
25
|
+
* 3. When signed in, detects org context from the ID token (`user_org`) and
|
|
26
|
+
* switches `resolvedBaseUrl` to `${baseUrl}/o` when the user is acting
|
|
27
|
+
* within an organisation.
|
|
28
|
+
* 4. In parallel (gated by `preferences`):
|
|
29
|
+
* - Fetches user + SCIM2 user profile (`preferences.user.fetchUserProfile !== false`)
|
|
30
|
+
* - Fetches current org + my orgs (`preferences.user.fetchOrganizations !== false`)
|
|
31
|
+
* - Fetches branding preference (`preferences.theme.inheritFromBranding !== false`)
|
|
32
|
+
* 5. Writes the full {@link ThunderIDSSRData} to `event.context.thunderid.ssr`
|
|
33
|
+
* so the Nuxt plugin can seed `useState` keys for zero-cost hydration.
|
|
34
|
+
*
|
|
35
|
+
* Each fetch is individually wrapped in try/catch so a broken SCIM or branding
|
|
36
|
+
* call never crashes SSR — the client layer can recover via the existing
|
|
37
|
+
* `/api/auth/*` routes.
|
|
38
|
+
*/
|
|
39
|
+
declare const _default: import("nitropack/types").NitroAppPlugin;
|
|
40
|
+
export default _default;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { getRequestURL } from "h3";
|
|
2
|
+
import { defineNitroPlugin } from "nitropack/runtime";
|
|
3
|
+
import { createLogger } from "../../utils/log.js";
|
|
4
|
+
import ThunderIDNuxtClient from "../ThunderIDNuxtClient.js";
|
|
5
|
+
import { verifyAndRehydrateSession } from "../utils/serverSession.js";
|
|
6
|
+
import { useRuntimeConfig } from "#imports";
|
|
7
|
+
const log = createLogger("thunderid-ssr");
|
|
8
|
+
const CALLBACK_PATH = "/api/auth/callback";
|
|
9
|
+
function resolveCallbackUrl(event) {
|
|
10
|
+
const url = getRequestURL(event, { xForwardedHost: true, xForwardedProto: true });
|
|
11
|
+
return `${url.origin}${CALLBACK_PATH}`;
|
|
12
|
+
}
|
|
13
|
+
export default defineNitroPlugin((nitro) => {
|
|
14
|
+
nitro.hooks.hook("request", async (event) => {
|
|
15
|
+
const client = ThunderIDNuxtClient.getInstance();
|
|
16
|
+
if (!client.isInitialized) {
|
|
17
|
+
const config2 = useRuntimeConfig(event);
|
|
18
|
+
const publicConfig2 = config2.public.thunderid;
|
|
19
|
+
const privateConfig = config2.thunderid;
|
|
20
|
+
if (!publicConfig2?.baseUrl || !publicConfig2?.clientId) {
|
|
21
|
+
log.error(
|
|
22
|
+
"Missing required config: baseUrl and clientId. Set NUXT_PUBLIC_THUNDERID_BASE_URL and NUXT_PUBLIC_THUNDERID_CLIENT_ID."
|
|
23
|
+
);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const sessionSecret2 = process.env["THUNDERID_SESSION_SECRET"] || privateConfig?.sessionSecret;
|
|
27
|
+
if (!sessionSecret2) {
|
|
28
|
+
if (process.env["NODE_ENV"] === "production") {
|
|
29
|
+
log.error(
|
|
30
|
+
"THUNDERID_SESSION_SECRET is required in production. Set it to a secure random string of at least 32 characters. Refusing to initialize ThunderID client."
|
|
31
|
+
);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
log.warn(
|
|
35
|
+
"THUNDERID_SESSION_SECRET is not set. Using an insecure default for development only. Set THUNDERID_SESSION_SECRET before deploying."
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
await client.initialize({
|
|
40
|
+
afterSignInUrl: resolveCallbackUrl(event),
|
|
41
|
+
afterSignOutUrl: publicConfig2.afterSignOutUrl || "/",
|
|
42
|
+
baseUrl: publicConfig2.baseUrl,
|
|
43
|
+
clientId: publicConfig2.clientId,
|
|
44
|
+
clientSecret: privateConfig?.clientSecret || void 0,
|
|
45
|
+
platform: publicConfig2.platform,
|
|
46
|
+
scopes: publicConfig2.scopes || ["openid", "profile"],
|
|
47
|
+
tokenRequest: publicConfig2.tokenRequest
|
|
48
|
+
});
|
|
49
|
+
} catch (err) {
|
|
50
|
+
log.error("Failed to initialize ThunderID client:", err);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const url = event.path || "";
|
|
55
|
+
if (url.startsWith("/api/") || url.startsWith("/_nuxt/") || url.startsWith("/__nuxt_")) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const config = useRuntimeConfig(event);
|
|
59
|
+
const publicConfig = config.public.thunderid;
|
|
60
|
+
const prefs = publicConfig?.preferences;
|
|
61
|
+
const sessionSecret = process.env["THUNDERID_SESSION_SECRET"] || config.thunderid?.sessionSecret;
|
|
62
|
+
const session = await verifyAndRehydrateSession(
|
|
63
|
+
event,
|
|
64
|
+
sessionSecret
|
|
65
|
+
);
|
|
66
|
+
if (!session) {
|
|
67
|
+
const eventContext2 = event.context;
|
|
68
|
+
eventContext2.thunderid = { isSignedIn: false, session: null };
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const baseUrl = publicConfig?.baseUrl ?? "";
|
|
72
|
+
let resolvedBaseUrl = baseUrl;
|
|
73
|
+
try {
|
|
74
|
+
if (session.organizationId) {
|
|
75
|
+
resolvedBaseUrl = `${baseUrl}/o`;
|
|
76
|
+
} else {
|
|
77
|
+
const idToken = await client.getDecodedIdToken(
|
|
78
|
+
session.sessionId
|
|
79
|
+
);
|
|
80
|
+
if (idToken?.["user_org"]) {
|
|
81
|
+
resolvedBaseUrl = `${baseUrl}/o`;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} catch {
|
|
85
|
+
}
|
|
86
|
+
const shouldFetchProfile = prefs?.user?.fetchUserProfile !== false;
|
|
87
|
+
const shouldFetchOrgs = prefs?.user?.fetchOrganizations !== false;
|
|
88
|
+
const shouldFetchBranding = prefs?.theme?.inheritFromBranding !== false;
|
|
89
|
+
const [userResult, userProfileResult, orgsResult, currentOrgResult, brandingResult] = await Promise.allSettled([
|
|
90
|
+
// Always fetch the basic user object (needed for ThunderIDAuthState.user)
|
|
91
|
+
client.getUser(session.sessionId),
|
|
92
|
+
// SCIM2 user profile (flattened + schemas)
|
|
93
|
+
shouldFetchProfile ? client.getUserProfile(session.sessionId) : Promise.resolve(null),
|
|
94
|
+
// User's organisations
|
|
95
|
+
shouldFetchOrgs ? client.getMyOrganizations(session.sessionId) : Promise.resolve([]),
|
|
96
|
+
// Current organisation (derived from the ID token)
|
|
97
|
+
shouldFetchOrgs ? client.getCurrentOrganization(session.sessionId) : Promise.resolve(null),
|
|
98
|
+
// Branding preference (does not require a session)
|
|
99
|
+
shouldFetchBranding ? client.getBrandingPreference({ baseUrl: resolvedBaseUrl }) : Promise.resolve(null)
|
|
100
|
+
]);
|
|
101
|
+
if (userResult.status === "rejected") {
|
|
102
|
+
log.debug("Failed to fetch user:", userResult.reason);
|
|
103
|
+
}
|
|
104
|
+
if (userProfileResult.status === "rejected") {
|
|
105
|
+
log.warn("Failed to fetch user profile (SCIM2):", userProfileResult.reason);
|
|
106
|
+
}
|
|
107
|
+
if (orgsResult.status === "rejected") {
|
|
108
|
+
log.warn("Failed to fetch my organisations:", orgsResult.reason);
|
|
109
|
+
}
|
|
110
|
+
if (currentOrgResult.status === "rejected") {
|
|
111
|
+
log.warn("Failed to resolve current organisation:", currentOrgResult.reason);
|
|
112
|
+
}
|
|
113
|
+
if (brandingResult.status === "rejected") {
|
|
114
|
+
log.warn("Failed to fetch branding preference:", brandingResult.reason);
|
|
115
|
+
}
|
|
116
|
+
const ssrData = {
|
|
117
|
+
brandingPreference: brandingResult.status === "fulfilled" ? brandingResult.value : null,
|
|
118
|
+
currentOrganization: currentOrgResult.status === "fulfilled" ? currentOrgResult.value : null,
|
|
119
|
+
isSignedIn: true,
|
|
120
|
+
myOrganizations: orgsResult.status === "fulfilled" && Array.isArray(orgsResult.value) ? orgsResult.value : [],
|
|
121
|
+
resolvedBaseUrl,
|
|
122
|
+
session,
|
|
123
|
+
user: userResult.status === "fulfilled" ? userResult.value : null,
|
|
124
|
+
userProfile: userProfileResult.status === "fulfilled" ? userProfileResult.value : null
|
|
125
|
+
};
|
|
126
|
+
const eventContext = event.context;
|
|
127
|
+
eventContext.thunderid = { isSignedIn: true, session, ssr: ssrData };
|
|
128
|
+
const authState = {
|
|
129
|
+
isLoading: false,
|
|
130
|
+
isSignedIn: true,
|
|
131
|
+
user: ssrData.user
|
|
132
|
+
};
|
|
133
|
+
eventContext["__thunderidAuth"] = authState;
|
|
134
|
+
});
|
|
135
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
|
|
3
|
+
*
|
|
4
|
+
* WSO2 LLC. licenses this file to you under the Apache License,
|
|
5
|
+
* Version 2.0 (the "License"); you may not use this file except
|
|
6
|
+
* in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing,
|
|
12
|
+
* software distributed under the License is distributed on an
|
|
13
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
* KIND, either express or implied. See the License for the
|
|
15
|
+
* specific language governing permissions and limitations
|
|
16
|
+
* under the License.
|
|
17
|
+
*/
|
|
18
|
+
import type { BrandingPreference } from '@thunderid/node';
|
|
19
|
+
/**
|
|
20
|
+
* GET /api/auth/branding
|
|
21
|
+
*
|
|
22
|
+
* Returns the branding preference for the current tenant / organisation context.
|
|
23
|
+
* Resolves the correct `baseUrl` (org-scoped if the session is inside an org).
|
|
24
|
+
* Does not require an authenticated session — unauthenticated callers receive
|
|
25
|
+
* the root-tenant branding.
|
|
26
|
+
*
|
|
27
|
+
* Used by `ThunderIDRoot.revalidateBranding` to refresh client-side branding
|
|
28
|
+
* state without a full page reload.
|
|
29
|
+
*/
|
|
30
|
+
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<BrandingPreference | null>>;
|
|
31
|
+
export default _default;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { defineEventHandler, createError } from "h3";
|
|
2
|
+
import ThunderIDNuxtClient from "../../../ThunderIDNuxtClient.js";
|
|
3
|
+
import { verifyAndRehydrateSession } from "../../../utils/serverSession.js";
|
|
4
|
+
import { useRuntimeConfig } from "#imports";
|
|
5
|
+
export default defineEventHandler(async (event) => {
|
|
6
|
+
const config = useRuntimeConfig(event);
|
|
7
|
+
const publicConfig = config.public.thunderid;
|
|
8
|
+
const sessionSecret = config.thunderid?.sessionSecret;
|
|
9
|
+
const baseUrl = publicConfig?.baseUrl ?? "";
|
|
10
|
+
let resolvedBaseUrl = baseUrl;
|
|
11
|
+
try {
|
|
12
|
+
const session = await verifyAndRehydrateSession(
|
|
13
|
+
event,
|
|
14
|
+
sessionSecret
|
|
15
|
+
);
|
|
16
|
+
if (session) {
|
|
17
|
+
if (session.organizationId) {
|
|
18
|
+
resolvedBaseUrl = `${baseUrl}/o`;
|
|
19
|
+
} else {
|
|
20
|
+
const client = ThunderIDNuxtClient.getInstance();
|
|
21
|
+
const idToken = await client.getDecodedIdToken(
|
|
22
|
+
session.sessionId
|
|
23
|
+
);
|
|
24
|
+
if (idToken?.["user_org"]) {
|
|
25
|
+
resolvedBaseUrl = `${baseUrl}/o`;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
} catch {
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const client = ThunderIDNuxtClient.getInstance();
|
|
33
|
+
return await client.getBrandingPreference({ baseUrl: resolvedBaseUrl });
|
|
34
|
+
} catch (err) {
|
|
35
|
+
throw createError({
|
|
36
|
+
statusCode: 500,
|
|
37
|
+
statusMessage: `Failed to retrieve branding preference: ${err instanceof Error ? err.message : String(err)}`
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
|
|
3
|
+
*
|
|
4
|
+
* WSO2 LLC. licenses this file to you under the Apache License,
|
|
5
|
+
* Version 2.0 (the "License"); you may not use this file except
|
|
6
|
+
* in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing,
|
|
12
|
+
* software distributed under the License is distributed on an
|
|
13
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
* KIND, either express or implied. See the License for the
|
|
15
|
+
* specific language governing permissions and limitations
|
|
16
|
+
* under the License.
|
|
17
|
+
*/
|
|
18
|
+
import type { Organization } from '@thunderid/node';
|
|
19
|
+
/**
|
|
20
|
+
* GET /api/auth/organizations/current
|
|
21
|
+
*
|
|
22
|
+
* Returns the organisation the authenticated user is currently acting within,
|
|
23
|
+
* derived from the session's ID token (`org_id` / `org_name` claims).
|
|
24
|
+
* Returns `null` when the user is not inside an organisation context.
|
|
25
|
+
*
|
|
26
|
+
* Used by `ThunderIDRoot.revalidateCurrentOrganization` callback.
|
|
27
|
+
*/
|
|
28
|
+
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<Organization | null>>;
|
|
29
|
+
export default _default;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { defineEventHandler, createError } from "h3";
|
|
2
|
+
import ThunderIDNuxtClient from "../../../ThunderIDNuxtClient.js";
|
|
3
|
+
import { verifyAndRehydrateSession } from "../../../utils/serverSession.js";
|
|
4
|
+
import { useRuntimeConfig } from "#imports";
|
|
5
|
+
export default defineEventHandler(async (event) => {
|
|
6
|
+
const config = useRuntimeConfig();
|
|
7
|
+
const sessionSecret = config.thunderid?.sessionSecret;
|
|
8
|
+
const session = await verifyAndRehydrateSession(
|
|
9
|
+
event,
|
|
10
|
+
sessionSecret
|
|
11
|
+
);
|
|
12
|
+
if (!session) {
|
|
13
|
+
throw createError({ statusCode: 401, statusMessage: "Unauthorized: Invalid or expired session." });
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const client = ThunderIDNuxtClient.getInstance();
|
|
17
|
+
return await client.getCurrentOrganization(session.sessionId);
|
|
18
|
+
} catch (err) {
|
|
19
|
+
throw createError({
|
|
20
|
+
statusCode: 500,
|
|
21
|
+
statusMessage: `Failed to retrieve current organisation: ${err instanceof Error ? err.message : String(err)}`
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
|
|
3
|
+
*
|
|
4
|
+
* WSO2 LLC. licenses this file to you under the Apache License,
|
|
5
|
+
* Version 2.0 (the "License"); you may not use this file except
|
|
6
|
+
* in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing,
|
|
12
|
+
* software distributed under the License is distributed on an
|
|
13
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
* KIND, either express or implied. See the License for the
|
|
15
|
+
* specific language governing permissions and limitations
|
|
16
|
+
* under the License.
|
|
17
|
+
*/
|
|
18
|
+
import type { OrganizationDetails } from '@thunderid/node';
|
|
19
|
+
/**
|
|
20
|
+
* GET /api/auth/organizations/:id
|
|
21
|
+
*
|
|
22
|
+
* Returns the details of a single organisation by its ID.
|
|
23
|
+
* Requires an active session.
|
|
24
|
+
*
|
|
25
|
+
* Mirrors `getOrganizationAction` in the Next.js SDK.
|
|
26
|
+
*/
|
|
27
|
+
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<OrganizationDetails>>;
|
|
28
|
+
export default _default;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { defineEventHandler, getRouterParam, createError } from "h3";
|
|
2
|
+
import ThunderIDNuxtClient from "../../../ThunderIDNuxtClient.js";
|
|
3
|
+
import { verifyAndRehydrateSession } from "../../../utils/serverSession.js";
|
|
4
|
+
import { useRuntimeConfig } from "#imports";
|
|
5
|
+
export default defineEventHandler(async (event) => {
|
|
6
|
+
const config = useRuntimeConfig();
|
|
7
|
+
const sessionSecret = config.thunderid?.sessionSecret;
|
|
8
|
+
const session = await verifyAndRehydrateSession(
|
|
9
|
+
event,
|
|
10
|
+
sessionSecret
|
|
11
|
+
);
|
|
12
|
+
if (!session) {
|
|
13
|
+
throw createError({ statusCode: 401, statusMessage: "Unauthorized: Invalid or expired session." });
|
|
14
|
+
}
|
|
15
|
+
const organizationId = getRouterParam(event, "id");
|
|
16
|
+
if (!organizationId) {
|
|
17
|
+
throw createError({ statusCode: 400, statusMessage: "Organization ID is required." });
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const client = ThunderIDNuxtClient.getInstance();
|
|
21
|
+
return await client.getOrganization(organizationId, session.sessionId);
|
|
22
|
+
} catch (err) {
|
|
23
|
+
throw createError({
|
|
24
|
+
statusCode: 500,
|
|
25
|
+
statusMessage: `Failed to retrieve organisation: ${err instanceof Error ? err.message : String(err)}`
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
|
|
3
|
+
*
|
|
4
|
+
* WSO2 LLC. licenses this file to you under the Apache License,
|
|
5
|
+
* Version 2.0 (the "License"); you may not use this file except
|
|
6
|
+
* in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing,
|
|
12
|
+
* software distributed under the License is distributed on an
|
|
13
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
* KIND, either express or implied. See the License for the
|
|
15
|
+
* specific language governing permissions and limitations
|
|
16
|
+
* under the License.
|
|
17
|
+
*/
|
|
18
|
+
import type { AllOrganizationsApiResponse } from '@thunderid/node';
|
|
19
|
+
/**
|
|
20
|
+
* GET /api/auth/organizations
|
|
21
|
+
*
|
|
22
|
+
* Returns all organisations accessible to the authenticated user (paginated).
|
|
23
|
+
* Used by `ThunderIDRoot.getAllOrganizations` callback.
|
|
24
|
+
*
|
|
25
|
+
* Mirrors `getAllOrganizations` server action in the Next.js SDK.
|
|
26
|
+
*/
|
|
27
|
+
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<AllOrganizationsApiResponse>>;
|
|
28
|
+
export default _default;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { defineEventHandler, createError } from "h3";
|
|
2
|
+
import ThunderIDNuxtClient from "../../../ThunderIDNuxtClient.js";
|
|
3
|
+
import { verifyAndRehydrateSession } from "../../../utils/serverSession.js";
|
|
4
|
+
import { useRuntimeConfig } from "#imports";
|
|
5
|
+
export default defineEventHandler(async (event) => {
|
|
6
|
+
const config = useRuntimeConfig();
|
|
7
|
+
const sessionSecret = config.thunderid?.sessionSecret;
|
|
8
|
+
const session = await verifyAndRehydrateSession(
|
|
9
|
+
event,
|
|
10
|
+
sessionSecret
|
|
11
|
+
);
|
|
12
|
+
if (!session) {
|
|
13
|
+
throw createError({ statusCode: 401, statusMessage: "Unauthorized: Invalid or expired session." });
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const client = ThunderIDNuxtClient.getInstance();
|
|
17
|
+
return await client.getAllOrganizations(void 0, session.sessionId);
|
|
18
|
+
} catch (err) {
|
|
19
|
+
throw createError({
|
|
20
|
+
statusCode: 500,
|
|
21
|
+
statusMessage: `Failed to retrieve all organisations: ${err instanceof Error ? err.message : String(err)}`
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
|
|
3
|
+
*
|
|
4
|
+
* WSO2 LLC. licenses this file to you under the Apache License,
|
|
5
|
+
* Version 2.0 (the "License"); you may not use this file except
|
|
6
|
+
* in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing,
|
|
12
|
+
* software distributed under the License is distributed on an
|
|
13
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
* KIND, either express or implied. See the License for the
|
|
15
|
+
* specific language governing permissions and limitations
|
|
16
|
+
* under the License.
|
|
17
|
+
*/
|
|
18
|
+
import type { Organization } from '@thunderid/node';
|
|
19
|
+
/**
|
|
20
|
+
* POST /api/auth/organizations
|
|
21
|
+
*
|
|
22
|
+
* Creates a new sub-organisation under the authenticated user's root organisation.
|
|
23
|
+
*
|
|
24
|
+
* Request body: {@link CreateOrganizationPayload}
|
|
25
|
+
* Response: {@link Organization}
|
|
26
|
+
*
|
|
27
|
+
* Mirrors `createOrganization` server action in the Next.js SDK.
|
|
28
|
+
*/
|
|
29
|
+
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<Organization>>;
|
|
30
|
+
export default _default;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { defineEventHandler, readBody, createError } from "h3";
|
|
2
|
+
import ThunderIDNuxtClient from "../../../ThunderIDNuxtClient.js";
|
|
3
|
+
import { verifyAndRehydrateSession } from "../../../utils/serverSession.js";
|
|
4
|
+
import { useRuntimeConfig } from "#imports";
|
|
5
|
+
export default defineEventHandler(async (event) => {
|
|
6
|
+
const config = useRuntimeConfig();
|
|
7
|
+
const sessionSecret = config.thunderid?.sessionSecret;
|
|
8
|
+
const session = await verifyAndRehydrateSession(
|
|
9
|
+
event,
|
|
10
|
+
sessionSecret
|
|
11
|
+
);
|
|
12
|
+
if (!session) {
|
|
13
|
+
throw createError({ statusCode: 401, statusMessage: "Unauthorized: Invalid or expired session." });
|
|
14
|
+
}
|
|
15
|
+
let payload;
|
|
16
|
+
try {
|
|
17
|
+
payload = await readBody(event);
|
|
18
|
+
} catch {
|
|
19
|
+
throw createError({ statusCode: 400, statusMessage: "Invalid request body." });
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const client = ThunderIDNuxtClient.getInstance();
|
|
23
|
+
return await client.createOrganization(payload, session.sessionId);
|
|
24
|
+
} catch (err) {
|
|
25
|
+
throw createError({
|
|
26
|
+
statusCode: 500,
|
|
27
|
+
statusMessage: `Failed to create organisation: ${err instanceof Error ? err.message : String(err)}`
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
|
|
3
|
+
*
|
|
4
|
+
* WSO2 LLC. licenses this file to you under the Apache License,
|
|
5
|
+
* Version 2.0 (the "License"); you may not use this file except
|
|
6
|
+
* in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing,
|
|
12
|
+
* software distributed under the License is distributed on an
|
|
13
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
* KIND, either express or implied. See the License for the
|
|
15
|
+
* specific language governing permissions and limitations
|
|
16
|
+
* under the License.
|
|
17
|
+
*/
|
|
18
|
+
import type { Organization } from '@thunderid/node';
|
|
19
|
+
/**
|
|
20
|
+
* GET /api/auth/organizations/me
|
|
21
|
+
*
|
|
22
|
+
* Returns the list of organisations the authenticated user is a member of.
|
|
23
|
+
* Used by `ThunderIDRoot.revalidateMyOrganizations` to refresh client-side state.
|
|
24
|
+
*
|
|
25
|
+
* Mirrors `getMyOrganizations` server action in the Next.js SDK.
|
|
26
|
+
*/
|
|
27
|
+
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<Organization[]>>;
|
|
28
|
+
export default _default;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { defineEventHandler, createError } from "h3";
|
|
2
|
+
import ThunderIDNuxtClient from "../../../ThunderIDNuxtClient.js";
|
|
3
|
+
import { verifyAndRehydrateSession } from "../../../utils/serverSession.js";
|
|
4
|
+
import { useRuntimeConfig } from "#imports";
|
|
5
|
+
export default defineEventHandler(async (event) => {
|
|
6
|
+
const config = useRuntimeConfig();
|
|
7
|
+
const sessionSecret = config.thunderid?.sessionSecret;
|
|
8
|
+
const session = await verifyAndRehydrateSession(
|
|
9
|
+
event,
|
|
10
|
+
sessionSecret
|
|
11
|
+
);
|
|
12
|
+
if (!session) {
|
|
13
|
+
throw createError({ statusCode: 401, statusMessage: "Unauthorized: Invalid or expired session." });
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const client = ThunderIDNuxtClient.getInstance();
|
|
17
|
+
return await client.getMyOrganizations(session.sessionId);
|
|
18
|
+
} catch (err) {
|
|
19
|
+
throw createError({
|
|
20
|
+
statusCode: 500,
|
|
21
|
+
statusMessage: `Failed to retrieve organisations: ${err instanceof Error ? err.message : String(err)}`
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
|
|
3
|
+
*
|
|
4
|
+
* WSO2 LLC. licenses this file to you under the Apache License,
|
|
5
|
+
* Version 2.0 (the "License"); you may not use this file except
|
|
6
|
+
* in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing,
|
|
12
|
+
* software distributed under the License is distributed on an
|
|
13
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
* KIND, either express or implied. See the License for the
|
|
15
|
+
* specific language governing permissions and limitations
|
|
16
|
+
* under the License.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* POST /api/auth/organizations/switch
|
|
20
|
+
*
|
|
21
|
+
* Performs an `organization_switch` token exchange for the given organisation,
|
|
22
|
+
* then re-issues the JWT session cookie so subsequent requests carry the new
|
|
23
|
+
* organisation context.
|
|
24
|
+
*
|
|
25
|
+
* Request body: `{ organization: Organization }`
|
|
26
|
+
*
|
|
27
|
+
* Mirrors `switchOrganization` server action in the Next.js SDK.
|
|
28
|
+
*/
|
|
29
|
+
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{
|
|
30
|
+
success: boolean;
|
|
31
|
+
}>>;
|
|
32
|
+
export default _default;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { defineEventHandler, readBody, createError } from "h3";
|
|
2
|
+
import ThunderIDNuxtClient from "../../../ThunderIDNuxtClient.js";
|
|
3
|
+
import { verifyAndRehydrateSession } from "../../../utils/serverSession.js";
|
|
4
|
+
import { issueSessionCookie } from "../../../utils/session.js";
|
|
5
|
+
import { useRuntimeConfig } from "#imports";
|
|
6
|
+
export default defineEventHandler(async (event) => {
|
|
7
|
+
const config = useRuntimeConfig();
|
|
8
|
+
const sessionSecret = config.thunderid?.sessionSecret;
|
|
9
|
+
const session = await verifyAndRehydrateSession(
|
|
10
|
+
event,
|
|
11
|
+
sessionSecret
|
|
12
|
+
);
|
|
13
|
+
if (!session) {
|
|
14
|
+
throw createError({ statusCode: 401, statusMessage: "Unauthorized: Invalid or expired session." });
|
|
15
|
+
}
|
|
16
|
+
const { sessionId } = session;
|
|
17
|
+
let organization;
|
|
18
|
+
try {
|
|
19
|
+
const body = await readBody(event);
|
|
20
|
+
organization = body.organization;
|
|
21
|
+
} catch {
|
|
22
|
+
throw createError({ statusCode: 400, statusMessage: "Invalid request body." });
|
|
23
|
+
}
|
|
24
|
+
if (!organization?.id) {
|
|
25
|
+
throw createError({ statusCode: 400, statusMessage: "organization.id is required." });
|
|
26
|
+
}
|
|
27
|
+
let tokenResponse;
|
|
28
|
+
try {
|
|
29
|
+
const client = ThunderIDNuxtClient.getInstance();
|
|
30
|
+
const response = await client.switchOrganization(organization, sessionId);
|
|
31
|
+
tokenResponse = response;
|
|
32
|
+
} catch (err) {
|
|
33
|
+
throw createError({
|
|
34
|
+
statusCode: 500,
|
|
35
|
+
statusMessage: `Organisation switch failed: ${err instanceof Error ? err.message : String(err)}`
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const runtimeConfig = useRuntimeConfig();
|
|
40
|
+
const runtimeSessionSecret = runtimeConfig.thunderid?.sessionSecret;
|
|
41
|
+
await issueSessionCookie(event, sessionId, tokenResponse, runtimeSessionSecret);
|
|
42
|
+
} catch (err) {
|
|
43
|
+
throw createError({
|
|
44
|
+
statusCode: 500,
|
|
45
|
+
statusMessage: `Failed to establish new session after organisation switch: ${err instanceof Error ? err.message : String(err)}`
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return { success: true };
|
|
49
|
+
});
|