@thunderid/nuxt 0.0.4 → 0.1.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 +1 -1
- package/dist/module.json +1 -1
- package/dist/runtime/server/ThunderIDNuxtClient.d.ts +2 -139
- package/dist/runtime/server/ThunderIDNuxtClient.js +29 -188
- package/dist/runtime/server/routes/auth/user/profile.patch.js +0 -7
- package/dist/runtime/types.d.ts +3 -3
- package/dist/runtime/utils/log.d.ts +2 -2
- package/dist/runtime/utils/log.js +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-

|
|
2
2
|
|
|
3
3
|
Nuxt SDK for ThunderID. Provides authentication for Nuxt 3 applications with support for SSR, server routes, and composables.
|
|
4
4
|
|
package/dist/module.json
CHANGED
|
@@ -15,172 +15,35 @@
|
|
|
15
15
|
* specific language governing permissions and limitations
|
|
16
16
|
* under the License.
|
|
17
17
|
*/
|
|
18
|
-
import { ThunderIDNodeClient, type IdToken, type Organization, type OrganizationDetails, type CreateOrganizationPayload, type Storage, type TokenExchangeRequestConfig, type TokenResponse, type User, type UserProfile, type UpdateMeProfileConfig, type AllOrganizationsApiResponse, type
|
|
18
|
+
import { ThunderIDNodeClient, type IdToken, type Organization, type OrganizationDetails, type CreateOrganizationPayload, type Storage, type TokenExchangeRequestConfig, type TokenResponse, type User, type UserProfile, type UpdateMeProfileConfig, type AllOrganizationsApiResponse, type EmbeddedFlowExecuteRequestPayload, type EmbeddedFlowExecuteResponse, type ExtendedAuthorizeRequestUrlParams, type SignUpOptions, type GetBrandingPreferenceConfig, type BrandingPreference } from '@thunderid/node';
|
|
19
19
|
import type { ThunderIDNuxtConfig, ThunderIDSessionPayload } from '../types.js';
|
|
20
|
-
/**
|
|
21
|
-
* Singleton ThunderID client for Nuxt applications.
|
|
22
|
-
*
|
|
23
|
-
* Mirrors the {@link ThunderIDNextClient} pattern: a single shared instance per
|
|
24
|
-
* server process that delegates OAuth/OIDC operations to an internal
|
|
25
|
-
* {@link LegacyThunderIDNodeClient}. The legacy client provisions its own default
|
|
26
|
-
* in-memory store (`MemoryCacheStore`) for PKCE state and tokens so that state
|
|
27
|
-
* persists across the sign-in → callback boundary.
|
|
28
|
-
*
|
|
29
|
-
* Consumers call {@link getInstance} directly from server routes and plugins —
|
|
30
|
-
* there is no per-request wrapper factory. Initialization happens once per
|
|
31
|
-
* process (guarded by {@link isInitialized}) from the `thunderid-init` Nitro
|
|
32
|
-
* plugin on the first request.
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* ```ts
|
|
36
|
-
* // In a Nitro API route:
|
|
37
|
-
* export default defineEventHandler(async (event) => {
|
|
38
|
-
* const client = ThunderIDNuxtClient.getInstance();
|
|
39
|
-
* return client.getUser(sessionId);
|
|
40
|
-
* });
|
|
41
|
-
* ```
|
|
42
|
-
*/
|
|
43
20
|
declare class ThunderIDNuxtClient extends ThunderIDNodeClient<ThunderIDNuxtConfig> {
|
|
44
21
|
private static instance;
|
|
45
|
-
private legacy;
|
|
46
22
|
isInitialized: boolean;
|
|
47
23
|
private constructor();
|
|
48
|
-
/**
|
|
49
|
-
* Get the singleton instance of ThunderIDNuxtClient.
|
|
50
|
-
*/
|
|
51
24
|
static getInstance(): ThunderIDNuxtClient;
|
|
52
|
-
/**
|
|
53
|
-
* Initializes the underlying legacy client with OAuth/OIDC settings derived
|
|
54
|
-
* from the Nuxt module config. Idempotent — repeated calls are no-ops after
|
|
55
|
-
* the first successful initialization.
|
|
56
|
-
*/
|
|
57
25
|
initialize(config: ThunderIDNuxtConfig, storage?: Storage): Promise<boolean>;
|
|
58
26
|
reInitialize(config: Partial<ThunderIDNuxtConfig>): Promise<boolean>;
|
|
59
|
-
/**
|
|
60
|
-
* Seeds the legacy in-memory token store from a verified session JWT payload.
|
|
61
|
-
*
|
|
62
|
-
* The signed session cookie is the source of truth for tokens in this SDK — it
|
|
63
|
-
* survives server restarts and new worker processes. The underlying
|
|
64
|
-
* {@link LegacyThunderIDNodeClient}, however, keeps tokens in a
|
|
65
|
-
* {@link MemoryCacheStore} keyed by `sessionId`, and its
|
|
66
|
-
* `getAccessToken` / `getUser` / `getDecodedIdToken` / `signOut` paths all
|
|
67
|
-
* read from that store. Without rehydration, those calls fail whenever the
|
|
68
|
-
* in-memory store and the cookie diverge (the classic case: `nuxi dev`
|
|
69
|
-
* restart while the browser still holds a valid session cookie).
|
|
70
|
-
*
|
|
71
|
-
* Writes the snake_case token shape the legacy helper expects
|
|
72
|
-
* (see `AuthenticationHelper.processTokenResponse`). Safe to call on every
|
|
73
|
-
* request — it's an in-memory write and the cookie always reflects the
|
|
74
|
-
* freshest tokens (the refresh path re-issues the cookie too).
|
|
75
|
-
*/
|
|
76
27
|
rehydrateSessionFromPayload(session: ThunderIDSessionPayload): Promise<void>;
|
|
77
|
-
/**
|
|
78
|
-
* Initiates the authorization code flow, handles an embedded sign-in step,
|
|
79
|
-
* or exchanges a code for tokens.
|
|
80
|
-
*
|
|
81
|
-
* Overload 1 — **redirect-flow** (existing callers like `signin.get.ts`):
|
|
82
|
-
* ```
|
|
83
|
-
* signIn(authURLCallback, sessionId, code?, sessionState?, state?, config?)
|
|
84
|
-
* ```
|
|
85
|
-
* Overload 2 — **embedded flow initiate** (flowId === ''):
|
|
86
|
-
* ```
|
|
87
|
-
* signIn({flowId: ''}, request, sessionId)
|
|
88
|
-
* ```
|
|
89
|
-
* Dispatches to `initializeEmbeddedSignInFlow`.
|
|
90
|
-
*
|
|
91
|
-
* Overload 3 — **embedded flow execute** (flowId set):
|
|
92
|
-
* ```
|
|
93
|
-
* signIn(payload, request, sessionId)
|
|
94
|
-
* ```
|
|
95
|
-
* Dispatches to `executeEmbeddedSignInFlow`.
|
|
96
|
-
*
|
|
97
|
-
* Overload 4 — **code exchange** (completion after embedded flow):
|
|
98
|
-
* ```
|
|
99
|
-
* signIn({code, state, session_state}, {}, sessionId)
|
|
100
|
-
* ```
|
|
101
|
-
* Falls through to the legacy redirect-flow code-exchange path.
|
|
102
|
-
*/
|
|
103
28
|
signIn(...args: any[]): Promise<any>;
|
|
104
|
-
/**
|
|
105
|
-
* Executes the embedded sign-up flow step.
|
|
106
|
-
* Mirrors `ThunderIDNextClient.signUp` with an `EmbeddedFlowExecuteRequestPayload`.
|
|
107
|
-
*/
|
|
108
29
|
signUp(options?: SignUpOptions): Promise<void>;
|
|
109
30
|
signUp(payload: EmbeddedFlowExecuteRequestPayload): Promise<EmbeddedFlowExecuteResponse>;
|
|
110
|
-
/**
|
|
111
|
-
* Returns the OAuth2 authorization URL.
|
|
112
|
-
* Used by the redirect-flow GET handler and the embedded-flow initiation path.
|
|
113
|
-
*
|
|
114
|
-
* Mirrors `ThunderIDNextClient.getAuthorizeRequestUrl`.
|
|
115
|
-
*/
|
|
116
31
|
getAuthorizeRequestUrl(customParams: ExtendedAuthorizeRequestUrlParams, userId?: string): Promise<string>;
|
|
117
|
-
/**
|
|
118
|
-
* Clears the session and returns the RP-Initiated Logout URL.
|
|
119
|
-
* Accepts either `(sessionId: string)` or `(options?, sessionId?, callback?)`.
|
|
120
|
-
*
|
|
121
|
-
* For ThunderIDV2 (Thunder), RP-Initiated Logout is not yet supported by the platform.
|
|
122
|
-
* Skip the /oidc/logout call and return afterSignOutUrl directly — the caller
|
|
123
|
-
* (signout.post.ts) is responsible for clearing session cookies.
|
|
124
|
-
*/
|
|
125
32
|
signOut(...args: any[]): Promise<string>;
|
|
126
33
|
getUser(sessionId?: string): Promise<User>;
|
|
127
34
|
getAccessToken(sessionId?: string): Promise<string>;
|
|
128
|
-
/**
|
|
129
|
-
* Decodes and returns the ID token claims for the given session.
|
|
130
|
-
* Exposed here (as on {@link ThunderIDNextClient}) so route handlers can
|
|
131
|
-
* access ID token claims without falling back to the legacy client.
|
|
132
|
-
*/
|
|
133
35
|
getDecodedIdToken(sessionId?: string, idToken?: string): Promise<IdToken>;
|
|
134
36
|
isSignedIn(sessionId?: string): Promise<boolean>;
|
|
135
37
|
exchangeToken(config: TokenExchangeRequestConfig, sessionId?: string): Promise<TokenResponse | Response>;
|
|
136
|
-
/**
|
|
137
|
-
* Fetches the flattened SCIM2 user profile for the given session.
|
|
138
|
-
* Mirrors `ThunderIDNextClient.getUserProfile` — calls `getScim2Me` +
|
|
139
|
-
* `getSchemas` + `generateFlattenedUserProfile` and falls back to
|
|
140
|
-
* `getUser` claims if SCIM2 is unavailable.
|
|
141
|
-
*/
|
|
142
38
|
getUserProfile(sessionId: string): Promise<UserProfile>;
|
|
143
|
-
/**
|
|
144
|
-
* Extracts the current organisation from the decoded ID token.
|
|
145
|
-
* Returns null when the user is not acting within an organisation.
|
|
146
|
-
*/
|
|
147
39
|
getCurrentOrganization(sessionId: string): Promise<Organization | null>;
|
|
148
|
-
/**
|
|
149
|
-
* Returns the list of organisations the authenticated user is a member of.
|
|
150
|
-
*/
|
|
151
40
|
getMyOrganizations(sessionId: string): Promise<Organization[]>;
|
|
152
|
-
/**
|
|
153
|
-
* Fetches the branding preference for the tenant / application.
|
|
154
|
-
* Delegates to the standalone `getBrandingPreference` API helper from
|
|
155
|
-
* `@thunderid/node`, which does not require an authenticated session.
|
|
156
|
-
*/
|
|
157
41
|
getBrandingPreference(config: GetBrandingPreferenceConfig): Promise<BrandingPreference>;
|
|
158
|
-
/**
|
|
159
|
-
* Updates the SCIM2 /Me profile for the authenticated user.
|
|
160
|
-
* Mirrors `ThunderIDNextClient.updateUserProfile`.
|
|
161
|
-
*/
|
|
162
42
|
updateUserProfile(config: UpdateMeProfileConfig, sessionId: string): Promise<User>;
|
|
163
|
-
/**
|
|
164
|
-
* Retrieves all organisations accessible to the authenticated user
|
|
165
|
-
* (paginated). Mirrors `ThunderIDNextClient.getAllOrganizations`.
|
|
166
|
-
*/
|
|
167
43
|
getAllOrganizations(options?: any, sessionId?: string): Promise<AllOrganizationsApiResponse>;
|
|
168
|
-
/**
|
|
169
|
-
* Creates a new sub-organisation. Mirrors `ThunderIDNextClient.createOrganization`.
|
|
170
|
-
*/
|
|
171
44
|
createOrganization(payload: CreateOrganizationPayload, sessionId: string): Promise<Organization>;
|
|
172
|
-
/**
|
|
173
|
-
* Fetches the details of a single organisation by ID.
|
|
174
|
-
* Mirrors `ThunderIDNextClient.getOrganization`.
|
|
175
|
-
*/
|
|
176
45
|
getOrganization(organizationId: string, sessionId: string): Promise<OrganizationDetails>;
|
|
177
|
-
/**
|
|
178
|
-
* Performs an organisation-switch token exchange and returns the new
|
|
179
|
-
* `TokenResponse`. The caller (the Nitro route) is responsible for
|
|
180
|
-
* persisting the new session cookie.
|
|
181
|
-
*
|
|
182
|
-
* Mirrors `ThunderIDNextClient.switchOrganization`.
|
|
183
|
-
*/
|
|
184
46
|
switchOrganization(organization: Organization, sessionId: string): Promise<TokenResponse | Response>;
|
|
47
|
+
getStorageManager(): any;
|
|
185
48
|
}
|
|
186
49
|
export default ThunderIDNuxtClient;
|
|
@@ -1,43 +1,26 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ThunderIDNodeClient,
|
|
3
|
-
LegacyThunderIDNodeClient,
|
|
4
|
-
Platform,
|
|
5
3
|
getBrandingPreference,
|
|
6
4
|
getMeOrganizations,
|
|
7
5
|
getAllOrganizations,
|
|
8
6
|
createOrganization,
|
|
9
7
|
getOrganization,
|
|
10
|
-
getScim2Me,
|
|
11
|
-
getSchemas,
|
|
12
|
-
flattenUserSchema,
|
|
13
|
-
generateFlattenedUserProfile,
|
|
14
|
-
updateMeProfile,
|
|
15
8
|
initializeEmbeddedSignInFlow,
|
|
16
9
|
executeEmbeddedSignInFlow,
|
|
17
10
|
executeEmbeddedSignUpFlow
|
|
18
11
|
} from "@thunderid/node";
|
|
19
12
|
class ThunderIDNuxtClient extends ThunderIDNodeClient {
|
|
20
13
|
static instance;
|
|
21
|
-
legacy;
|
|
22
14
|
isInitialized = false;
|
|
23
15
|
constructor() {
|
|
24
16
|
super();
|
|
25
|
-
this.legacy = new LegacyThunderIDNodeClient();
|
|
26
17
|
}
|
|
27
|
-
/**
|
|
28
|
-
* Get the singleton instance of ThunderIDNuxtClient.
|
|
29
|
-
*/
|
|
30
18
|
static getInstance() {
|
|
31
19
|
if (!ThunderIDNuxtClient.instance) {
|
|
32
20
|
ThunderIDNuxtClient.instance = new ThunderIDNuxtClient();
|
|
33
21
|
}
|
|
34
22
|
return ThunderIDNuxtClient.instance;
|
|
35
23
|
}
|
|
36
|
-
/**
|
|
37
|
-
* Initializes the underlying legacy client with OAuth/OIDC settings derived
|
|
38
|
-
* from the Nuxt module config. Idempotent — repeated calls are no-ops after
|
|
39
|
-
* the first successful initialization.
|
|
40
|
-
*/
|
|
41
24
|
async initialize(config, storage) {
|
|
42
25
|
if (this.isInitialized) {
|
|
43
26
|
return true;
|
|
@@ -49,40 +32,22 @@ class ThunderIDNuxtClient extends ThunderIDNodeClient {
|
|
|
49
32
|
clientId: config.clientId,
|
|
50
33
|
clientSecret: config.clientSecret || void 0,
|
|
51
34
|
enablePKCE: true,
|
|
52
|
-
platform: config.platform,
|
|
53
35
|
scopes: config.scopes || ["openid", "profile"],
|
|
54
36
|
tokenRequest: config.tokenRequest
|
|
55
37
|
};
|
|
56
|
-
const result = await
|
|
38
|
+
const result = await super.initialize(authConfig, storage);
|
|
57
39
|
this.isInitialized = true;
|
|
58
40
|
return result;
|
|
59
41
|
}
|
|
60
42
|
async reInitialize(config) {
|
|
61
|
-
await
|
|
43
|
+
await super.reInitialize(config);
|
|
62
44
|
return true;
|
|
63
45
|
}
|
|
64
|
-
/**
|
|
65
|
-
* Seeds the legacy in-memory token store from a verified session JWT payload.
|
|
66
|
-
*
|
|
67
|
-
* The signed session cookie is the source of truth for tokens in this SDK — it
|
|
68
|
-
* survives server restarts and new worker processes. The underlying
|
|
69
|
-
* {@link LegacyThunderIDNodeClient}, however, keeps tokens in a
|
|
70
|
-
* {@link MemoryCacheStore} keyed by `sessionId`, and its
|
|
71
|
-
* `getAccessToken` / `getUser` / `getDecodedIdToken` / `signOut` paths all
|
|
72
|
-
* read from that store. Without rehydration, those calls fail whenever the
|
|
73
|
-
* in-memory store and the cookie diverge (the classic case: `nuxi dev`
|
|
74
|
-
* restart while the browser still holds a valid session cookie).
|
|
75
|
-
*
|
|
76
|
-
* Writes the snake_case token shape the legacy helper expects
|
|
77
|
-
* (see `AuthenticationHelper.processTokenResponse`). Safe to call on every
|
|
78
|
-
* request — it's an in-memory write and the cookie always reflects the
|
|
79
|
-
* freshest tokens (the refresh path re-issues the cookie too).
|
|
80
|
-
*/
|
|
81
46
|
async rehydrateSessionFromPayload(session) {
|
|
82
47
|
if (!this.isInitialized || !session?.sessionId || !session?.accessToken) {
|
|
83
48
|
return;
|
|
84
49
|
}
|
|
85
|
-
const storageManager =
|
|
50
|
+
const storageManager = this.getStorageManager();
|
|
86
51
|
const iatSeconds = typeof session.iat === "number" ? session.iat : Math.floor(Date.now() / 1e3);
|
|
87
52
|
const expiresInSeconds = typeof session.accessTokenExpiresAt === "number" ? Math.max(0, session.accessTokenExpiresAt - iatSeconds) : 3600;
|
|
88
53
|
await storageManager.setSessionData(
|
|
@@ -99,38 +64,12 @@ class ThunderIDNuxtClient extends ThunderIDNodeClient {
|
|
|
99
64
|
session.sessionId
|
|
100
65
|
);
|
|
101
66
|
}
|
|
102
|
-
/**
|
|
103
|
-
* Initiates the authorization code flow, handles an embedded sign-in step,
|
|
104
|
-
* or exchanges a code for tokens.
|
|
105
|
-
*
|
|
106
|
-
* Overload 1 — **redirect-flow** (existing callers like `signin.get.ts`):
|
|
107
|
-
* ```
|
|
108
|
-
* signIn(authURLCallback, sessionId, code?, sessionState?, state?, config?)
|
|
109
|
-
* ```
|
|
110
|
-
* Overload 2 — **embedded flow initiate** (flowId === ''):
|
|
111
|
-
* ```
|
|
112
|
-
* signIn({flowId: ''}, request, sessionId)
|
|
113
|
-
* ```
|
|
114
|
-
* Dispatches to `initializeEmbeddedSignInFlow`.
|
|
115
|
-
*
|
|
116
|
-
* Overload 3 — **embedded flow execute** (flowId set):
|
|
117
|
-
* ```
|
|
118
|
-
* signIn(payload, request, sessionId)
|
|
119
|
-
* ```
|
|
120
|
-
* Dispatches to `executeEmbeddedSignInFlow`.
|
|
121
|
-
*
|
|
122
|
-
* Overload 4 — **code exchange** (completion after embedded flow):
|
|
123
|
-
* ```
|
|
124
|
-
* signIn({code, state, session_state}, {}, sessionId)
|
|
125
|
-
* ```
|
|
126
|
-
* Falls through to the legacy redirect-flow code-exchange path.
|
|
127
|
-
*/
|
|
128
67
|
signIn(...args) {
|
|
129
68
|
const arg0 = args[0];
|
|
130
69
|
if (typeof arg0 === "object" && arg0 !== null && "flowId" in arg0) {
|
|
131
70
|
const sessionId = args[2];
|
|
132
71
|
if (arg0.flowId === "") {
|
|
133
|
-
return this.
|
|
72
|
+
return this.getSignInUrl(
|
|
134
73
|
{ client_secret: "{{clientSecret}}", response_mode: "direct" },
|
|
135
74
|
sessionId
|
|
136
75
|
).then((authorizeUrl) => {
|
|
@@ -153,24 +92,18 @@ class ThunderIDNuxtClient extends ThunderIDNodeClient {
|
|
|
153
92
|
const sessionState = typeof payload.session_state === "string" ? payload.session_state : void 0;
|
|
154
93
|
const state = typeof payload.state === "string" ? payload.state : void 0;
|
|
155
94
|
const extraParams = {};
|
|
156
|
-
if (code)
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
extraParams.session_state = sessionState;
|
|
161
|
-
}
|
|
162
|
-
if (state) {
|
|
163
|
-
extraParams.state = state;
|
|
164
|
-
}
|
|
165
|
-
return this.legacy.signIn(args[3], args[2], code, sessionState, state, extraParams);
|
|
95
|
+
if (code) extraParams.code = code;
|
|
96
|
+
if (sessionState) extraParams.session_state = sessionState;
|
|
97
|
+
if (state) extraParams.state = state;
|
|
98
|
+
return super.signIn(args[3], args[2], code, sessionState, state, extraParams);
|
|
166
99
|
}
|
|
167
|
-
return
|
|
100
|
+
return super.signIn(args[0], args[1], args[2], args[3], args[4], args[5]);
|
|
168
101
|
}
|
|
169
102
|
async signUp(payloadOrOptions) {
|
|
170
103
|
if (!payloadOrOptions || !("flowType" in payloadOrOptions)) {
|
|
171
104
|
return void 0;
|
|
172
105
|
}
|
|
173
|
-
const configData =
|
|
106
|
+
const configData = this.getStorageManager().getConfigData();
|
|
174
107
|
const baseUrl = configData?.baseUrl;
|
|
175
108
|
const response = await executeEmbeddedSignUpFlow({
|
|
176
109
|
baseUrl,
|
|
@@ -178,86 +111,32 @@ class ThunderIDNuxtClient extends ThunderIDNodeClient {
|
|
|
178
111
|
});
|
|
179
112
|
return response;
|
|
180
113
|
}
|
|
181
|
-
/**
|
|
182
|
-
* Returns the OAuth2 authorization URL.
|
|
183
|
-
* Used by the redirect-flow GET handler and the embedded-flow initiation path.
|
|
184
|
-
*
|
|
185
|
-
* Mirrors `ThunderIDNextClient.getAuthorizeRequestUrl`.
|
|
186
|
-
*/
|
|
187
114
|
async getAuthorizeRequestUrl(customParams, userId) {
|
|
188
|
-
return this.
|
|
115
|
+
return this.getSignInUrl(customParams, userId);
|
|
189
116
|
}
|
|
190
|
-
/**
|
|
191
|
-
* Clears the session and returns the RP-Initiated Logout URL.
|
|
192
|
-
* Accepts either `(sessionId: string)` or `(options?, sessionId?, callback?)`.
|
|
193
|
-
*
|
|
194
|
-
* For ThunderIDV2 (Thunder), RP-Initiated Logout is not yet supported by the platform.
|
|
195
|
-
* Skip the /oidc/logout call and return afterSignOutUrl directly — the caller
|
|
196
|
-
* (signout.post.ts) is responsible for clearing session cookies.
|
|
197
|
-
*/
|
|
198
117
|
async signOut(...args) {
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
if (configData?.platform === Platform.ThunderIDV2) {
|
|
202
|
-
return configData?.afterSignOutUrl || configData?.afterSignInUrl || "/";
|
|
203
|
-
}
|
|
204
|
-
return this.legacy.signOut(sessionId);
|
|
118
|
+
const configData = this.getStorageManager().getConfigData();
|
|
119
|
+
return configData?.afterSignOutUrl || configData?.afterSignInUrl || "/";
|
|
205
120
|
}
|
|
206
121
|
getUser(sessionId) {
|
|
207
|
-
return
|
|
122
|
+
return super.getUser(sessionId);
|
|
208
123
|
}
|
|
209
124
|
getAccessToken(sessionId) {
|
|
210
|
-
return
|
|
125
|
+
return super.getAccessToken(sessionId);
|
|
211
126
|
}
|
|
212
|
-
/**
|
|
213
|
-
* Decodes and returns the ID token claims for the given session.
|
|
214
|
-
* Exposed here (as on {@link ThunderIDNextClient}) so route handlers can
|
|
215
|
-
* access ID token claims without falling back to the legacy client.
|
|
216
|
-
*/
|
|
217
127
|
getDecodedIdToken(sessionId, idToken) {
|
|
218
|
-
return
|
|
128
|
+
return super.getDecodedIdToken(sessionId, idToken);
|
|
219
129
|
}
|
|
220
130
|
isSignedIn(sessionId) {
|
|
221
|
-
return
|
|
131
|
+
return super.isSignedIn(sessionId);
|
|
222
132
|
}
|
|
223
133
|
exchangeToken(config, sessionId) {
|
|
224
|
-
return
|
|
134
|
+
return super.exchangeToken(config, sessionId);
|
|
225
135
|
}
|
|
226
|
-
/**
|
|
227
|
-
* Fetches the flattened SCIM2 user profile for the given session.
|
|
228
|
-
* Mirrors `ThunderIDNextClient.getUserProfile` — calls `getScim2Me` +
|
|
229
|
-
* `getSchemas` + `generateFlattenedUserProfile` and falls back to
|
|
230
|
-
* `getUser` claims if SCIM2 is unavailable.
|
|
231
|
-
*/
|
|
232
136
|
async getUserProfile(sessionId) {
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
const baseUrl = configData?.baseUrl ?? "";
|
|
236
|
-
if (configData?.platform === Platform.ThunderIDV2) {
|
|
237
|
-
const user = await this.getUser(sessionId);
|
|
238
|
-
return { flattenedProfile: user, profile: user, schemas: [] };
|
|
239
|
-
}
|
|
240
|
-
try {
|
|
241
|
-
const authHeaders = { Authorization: `Bearer ${accessToken}` };
|
|
242
|
-
const [profile, schemas] = await Promise.all([
|
|
243
|
-
getScim2Me({ baseUrl, headers: authHeaders }),
|
|
244
|
-
getSchemas({ baseUrl, headers: authHeaders })
|
|
245
|
-
]);
|
|
246
|
-
const processedSchemas = flattenUserSchema(schemas);
|
|
247
|
-
return {
|
|
248
|
-
flattenedProfile: generateFlattenedUserProfile(profile, processedSchemas),
|
|
249
|
-
profile,
|
|
250
|
-
schemas: processedSchemas
|
|
251
|
-
};
|
|
252
|
-
} catch {
|
|
253
|
-
const user = await this.getUser(sessionId);
|
|
254
|
-
return { flattenedProfile: user, profile: user, schemas: [] };
|
|
255
|
-
}
|
|
137
|
+
const user = await this.getUser(sessionId);
|
|
138
|
+
return { flattenedProfile: user, profile: user, schemas: [] };
|
|
256
139
|
}
|
|
257
|
-
/**
|
|
258
|
-
* Extracts the current organisation from the decoded ID token.
|
|
259
|
-
* Returns null when the user is not acting within an organisation.
|
|
260
|
-
*/
|
|
261
140
|
async getCurrentOrganization(sessionId) {
|
|
262
141
|
try {
|
|
263
142
|
const idToken = await this.getDecodedIdToken(sessionId);
|
|
@@ -273,65 +152,35 @@ class ThunderIDNuxtClient extends ThunderIDNodeClient {
|
|
|
273
152
|
return null;
|
|
274
153
|
}
|
|
275
154
|
}
|
|
276
|
-
/**
|
|
277
|
-
* Returns the list of organisations the authenticated user is a member of.
|
|
278
|
-
*/
|
|
279
155
|
async getMyOrganizations(sessionId) {
|
|
280
156
|
const accessToken = await this.getAccessToken(sessionId);
|
|
281
|
-
const configData =
|
|
157
|
+
const configData = this.getStorageManager().getConfigData();
|
|
282
158
|
const baseUrl = configData?.baseUrl ?? "";
|
|
283
159
|
return getMeOrganizations({
|
|
284
160
|
baseUrl,
|
|
285
161
|
headers: { Authorization: `Bearer ${accessToken}` }
|
|
286
162
|
});
|
|
287
163
|
}
|
|
288
|
-
/**
|
|
289
|
-
* Fetches the branding preference for the tenant / application.
|
|
290
|
-
* Delegates to the standalone `getBrandingPreference` API helper from
|
|
291
|
-
* `@thunderid/node`, which does not require an authenticated session.
|
|
292
|
-
*/
|
|
293
164
|
// eslint-disable-next-line class-methods-use-this
|
|
294
165
|
async getBrandingPreference(config) {
|
|
295
166
|
return getBrandingPreference(config);
|
|
296
167
|
}
|
|
297
|
-
/**
|
|
298
|
-
* Updates the SCIM2 /Me profile for the authenticated user.
|
|
299
|
-
* Mirrors `ThunderIDNextClient.updateUserProfile`.
|
|
300
|
-
*/
|
|
301
168
|
async updateUserProfile(config, sessionId) {
|
|
302
|
-
|
|
303
|
-
const configData = await this.legacy.getConfigData?.();
|
|
304
|
-
const baseUrl = configData?.baseUrl ?? "";
|
|
305
|
-
if (configData?.platform === Platform.ThunderIDV2) {
|
|
306
|
-
throw new Error("Profile updates are not supported for the ThunderIDV2 (Thunder) platform.");
|
|
307
|
-
}
|
|
308
|
-
return updateMeProfile({
|
|
309
|
-
...config,
|
|
310
|
-
// pass-through, includes payload
|
|
311
|
-
baseUrl,
|
|
312
|
-
headers: { ...config.headers, Authorization: `Bearer ${accessToken}` }
|
|
313
|
-
});
|
|
169
|
+
throw new Error("Profile updates are not supported for the ThunderID platform.");
|
|
314
170
|
}
|
|
315
|
-
/**
|
|
316
|
-
* Retrieves all organisations accessible to the authenticated user
|
|
317
|
-
* (paginated). Mirrors `ThunderIDNextClient.getAllOrganizations`.
|
|
318
|
-
*/
|
|
319
171
|
async getAllOrganizations(options, sessionId) {
|
|
320
172
|
const resolvedSessionId = sessionId ?? "";
|
|
321
173
|
const accessToken = await this.getAccessToken(resolvedSessionId);
|
|
322
|
-
const configData =
|
|
174
|
+
const configData = this.getStorageManager().getConfigData();
|
|
323
175
|
const baseUrl = configData?.baseUrl ?? "";
|
|
324
176
|
return getAllOrganizations({
|
|
325
177
|
baseUrl,
|
|
326
178
|
headers: { Authorization: `Bearer ${accessToken}` }
|
|
327
179
|
});
|
|
328
180
|
}
|
|
329
|
-
/**
|
|
330
|
-
* Creates a new sub-organisation. Mirrors `ThunderIDNextClient.createOrganization`.
|
|
331
|
-
*/
|
|
332
181
|
async createOrganization(payload, sessionId) {
|
|
333
182
|
const accessToken = await this.getAccessToken(sessionId);
|
|
334
|
-
const configData =
|
|
183
|
+
const configData = this.getStorageManager().getConfigData();
|
|
335
184
|
const baseUrl = configData?.baseUrl ?? "";
|
|
336
185
|
return createOrganization({
|
|
337
186
|
baseUrl,
|
|
@@ -339,13 +188,9 @@ class ThunderIDNuxtClient extends ThunderIDNodeClient {
|
|
|
339
188
|
payload
|
|
340
189
|
});
|
|
341
190
|
}
|
|
342
|
-
/**
|
|
343
|
-
* Fetches the details of a single organisation by ID.
|
|
344
|
-
* Mirrors `ThunderIDNextClient.getOrganization`.
|
|
345
|
-
*/
|
|
346
191
|
async getOrganization(organizationId, sessionId) {
|
|
347
192
|
const accessToken = await this.getAccessToken(sessionId);
|
|
348
|
-
const configData =
|
|
193
|
+
const configData = this.getStorageManager().getConfigData();
|
|
349
194
|
const baseUrl = configData?.baseUrl ?? "";
|
|
350
195
|
return getOrganization({
|
|
351
196
|
baseUrl,
|
|
@@ -353,13 +198,6 @@ class ThunderIDNuxtClient extends ThunderIDNodeClient {
|
|
|
353
198
|
organizationId
|
|
354
199
|
});
|
|
355
200
|
}
|
|
356
|
-
/**
|
|
357
|
-
* Performs an organisation-switch token exchange and returns the new
|
|
358
|
-
* `TokenResponse`. The caller (the Nitro route) is responsible for
|
|
359
|
-
* persisting the new session cookie.
|
|
360
|
-
*
|
|
361
|
-
* Mirrors `ThunderIDNextClient.switchOrganization`.
|
|
362
|
-
*/
|
|
363
201
|
async switchOrganization(organization, sessionId) {
|
|
364
202
|
if (!organization.id) {
|
|
365
203
|
throw new Error("Organization ID is required for switching organizations.");
|
|
@@ -378,7 +216,10 @@ class ThunderIDNuxtClient extends ThunderIDNodeClient {
|
|
|
378
216
|
returnsSession: true,
|
|
379
217
|
signInRequired: true
|
|
380
218
|
};
|
|
381
|
-
return this.
|
|
219
|
+
return this.exchangeToken(exchangeConfig, sessionId);
|
|
220
|
+
}
|
|
221
|
+
getStorageManager() {
|
|
222
|
+
return super.getStorageManager();
|
|
382
223
|
}
|
|
383
224
|
}
|
|
384
225
|
export default ThunderIDNuxtClient;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Platform } from "@thunderid/node";
|
|
2
1
|
import { defineEventHandler, readBody, createError } from "h3";
|
|
3
2
|
import ThunderIDNuxtClient from "../../../ThunderIDNuxtClient.js";
|
|
4
3
|
import { verifyAndRehydrateSession } from "../../../utils/serverSession.js";
|
|
@@ -8,12 +7,6 @@ export default defineEventHandler(
|
|
|
8
7
|
const config = useRuntimeConfig();
|
|
9
8
|
const sessionSecret = config.thunderid?.sessionSecret;
|
|
10
9
|
const publicConfig = config.public.thunderid;
|
|
11
|
-
if (publicConfig?.platform === Platform.ThunderIDV2) {
|
|
12
|
-
throw createError({
|
|
13
|
-
statusCode: 501,
|
|
14
|
-
statusMessage: "Profile updates are not supported for the ThunderIDV2 (Thunder) platform."
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
10
|
const session = await verifyAndRehydrateSession(
|
|
18
11
|
event,
|
|
19
12
|
sessionSecret
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -34,10 +34,10 @@ export interface ThunderIDNuxtConfig {
|
|
|
34
34
|
baseUrl?: string;
|
|
35
35
|
/** OAuth2 Client ID */
|
|
36
36
|
clientId?: string;
|
|
37
|
-
/** OAuth2 Client Secret (server-only, use
|
|
37
|
+
/** OAuth2 Client Secret (server-only, use THUNDERID_CLIENT_SECRET env var) */
|
|
38
38
|
clientSecret?: string;
|
|
39
39
|
/**
|
|
40
|
-
* Identity platform variant. Set to `Platform.
|
|
40
|
+
* Identity platform variant. Set to `Platform.ThunderID` when connecting to
|
|
41
41
|
* a Thunder (ThunderIDV2) instance. Forwarded to the underlying Node client so
|
|
42
42
|
* platform-specific behaviours (e.g. issuer resolution) apply correctly.
|
|
43
43
|
*/
|
|
@@ -73,7 +73,7 @@ export interface ThunderIDNuxtConfig {
|
|
|
73
73
|
};
|
|
74
74
|
/** OAuth2 scopes to request */
|
|
75
75
|
scopes?: string[];
|
|
76
|
-
/** Secret for signing session JWTs (use
|
|
76
|
+
/** Secret for signing session JWTs (use THUNDERID_SESSION_SECRET env var) */
|
|
77
77
|
sessionSecret?: string;
|
|
78
78
|
/**
|
|
79
79
|
* Optional override for the redirect-based sign-in URL. Reserved for
|
|
@@ -26,14 +26,14 @@ export declare function maskToken(token: string): string;
|
|
|
26
26
|
/**
|
|
27
27
|
* Create a namespaced logger for a specific SDK subsystem.
|
|
28
28
|
*
|
|
29
|
-
* Debug output is suppressed unless the `
|
|
29
|
+
* Debug output is suppressed unless the `THUNDERID_DEBUG` environment
|
|
30
30
|
* variable is set (any truthy value).
|
|
31
31
|
*
|
|
32
32
|
* @example
|
|
33
33
|
* ```ts
|
|
34
34
|
* const log = createLogger('session');
|
|
35
35
|
* log.info('Session created for', maskToken(accessToken));
|
|
36
|
-
* log.debug('Full payload', payload); // only logged when
|
|
36
|
+
* log.debug('Full payload', payload); // only logged when THUNDERID_DEBUG=true
|
|
37
37
|
* ```
|
|
38
38
|
*/
|
|
39
39
|
export declare function createLogger(subsystem: string): {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thunderid/nuxt",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Nuxt SDK for ThunderID",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"thunderid",
|
|
@@ -61,22 +61,22 @@
|
|
|
61
61
|
"directory": "packages/nuxt"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@nuxt/kit": "3.
|
|
64
|
+
"@nuxt/kit": "3.21.6",
|
|
65
65
|
"defu": "6.1.5",
|
|
66
66
|
"jose": "5.2.0",
|
|
67
|
-
"@thunderid/node": "^0.0
|
|
68
|
-
"@thunderid/
|
|
69
|
-
"@thunderid/
|
|
67
|
+
"@thunderid/node": "^0.1.0",
|
|
68
|
+
"@thunderid/browser": "^0.1.0",
|
|
69
|
+
"@thunderid/vue": "^0.1.0"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
|
-
"@nuxt/devtools": "2.4
|
|
72
|
+
"@nuxt/devtools": "2.6.4",
|
|
73
73
|
"@nuxt/module-builder": "1.0.1",
|
|
74
|
-
"@nuxt/schema": "3.
|
|
74
|
+
"@nuxt/schema": "3.21.6",
|
|
75
75
|
"@nuxt/test-utils": "3.17.2",
|
|
76
76
|
"@types/node": "24.7.2",
|
|
77
77
|
"eslint": "9.39.4",
|
|
78
78
|
"h3": "1.15.11",
|
|
79
|
-
"nuxt": "3.
|
|
79
|
+
"nuxt": "3.21.6",
|
|
80
80
|
"typescript": "5.9.3",
|
|
81
81
|
"vitest": "4.1.3",
|
|
82
82
|
"@thunderid/eslint-plugin": "^0.0.0",
|