@thunderid/express 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.
Files changed (43) hide show
  1. package/README.md +1 -1
  2. package/dist/ThunderIDExpressClient.d.ts +11 -9
  3. package/dist/ThunderIDExpressClient.d.ts.map +1 -1
  4. package/dist/cjs/index.cjs +306 -172
  5. package/dist/{__legacy__/constants/logger-config.d.ts → constants/CookieConfig.d.ts} +11 -11
  6. package/dist/constants/CookieConfig.d.ts.map +1 -0
  7. package/dist/edge/index.js +300 -172
  8. package/dist/index.d.ts +6 -2
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +300 -172
  11. package/dist/middleware/authentication.d.ts +66 -0
  12. package/dist/middleware/authentication.d.ts.map +1 -0
  13. package/dist/middleware/flow.d.ts +50 -0
  14. package/dist/middleware/flow.d.ts.map +1 -0
  15. package/dist/{__legacy__/middleware/protect-route.d.ts → middleware/protect.d.ts} +12 -5
  16. package/dist/middleware/protect.d.ts.map +1 -0
  17. package/dist/models/config.d.ts +28 -9
  18. package/dist/models/config.d.ts.map +1 -1
  19. package/dist/{__legacy__/models/protect-route.d.ts → models/protectRoute.d.ts} +6 -3
  20. package/dist/models/protectRoute.d.ts.map +1 -0
  21. package/dist/{__legacy__/constants/index.d.ts → utils/expressUtils.d.ts} +9 -4
  22. package/dist/utils/expressUtils.d.ts.map +1 -0
  23. package/package.json +7 -5
  24. package/dist/__legacy__/client.d.ts +0 -46
  25. package/dist/__legacy__/client.d.ts.map +0 -1
  26. package/dist/__legacy__/constants/default-options.d.ts +0 -26
  27. package/dist/__legacy__/constants/default-options.d.ts.map +0 -1
  28. package/dist/__legacy__/constants/index.d.ts.map +0 -1
  29. package/dist/__legacy__/constants/logger-config.d.ts.map +0 -1
  30. package/dist/__legacy__/middleware/authentication.d.ts +0 -23
  31. package/dist/__legacy__/middleware/authentication.d.ts.map +0 -1
  32. package/dist/__legacy__/middleware/index.d.ts +0 -20
  33. package/dist/__legacy__/middleware/index.d.ts.map +0 -1
  34. package/dist/__legacy__/middleware/protect-route.d.ts.map +0 -1
  35. package/dist/__legacy__/models/client-config.d.ts +0 -33
  36. package/dist/__legacy__/models/client-config.d.ts.map +0 -1
  37. package/dist/__legacy__/models/data.d.ts +0 -21
  38. package/dist/__legacy__/models/data.d.ts.map +0 -1
  39. package/dist/__legacy__/models/index.d.ts +0 -21
  40. package/dist/__legacy__/models/index.d.ts.map +0 -1
  41. package/dist/__legacy__/models/protect-route.d.ts.map +0 -1
  42. package/dist/__legacy__/utils/express-utils.d.ts +0 -22
  43. package/dist/__legacy__/utils/express-utils.d.ts.map +0 -1
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- ![ThunderID Express SDK](https://raw.githubusercontent.com/thunder-id/thunderid/refs/heads/main/docs/content/sdks/assets/images/%40thunderid%3Aexpress_sdk_banner.png)
1
+ ![ThunderID Express SDK](https://raw.githubusercontent.com/thunder-id/thunderid/refs/heads/main/docs/static/assets/images/readme/repo-banner-express-sdk.png)
2
2
 
3
3
  Express.js SDK for ThunderID. Provides authentication middleware for Express applications.
4
4
 
@@ -15,15 +15,17 @@
15
15
  * specific language governing permissions and limitations
16
16
  * under the License.
17
17
  */
18
- import { LegacyThunderIDNodeClient } from '@thunderid/node';
19
- import { ThunderIDExpressConfig } from './models/config';
20
- /**
21
- * Base class for implementing ThunderID in Express.js based applications.
22
- * This class provides the core functionality for managing user authentication and sessions.
23
- *
24
- * @typeParam T - Configuration type that extends ThunderIDExpressConfig.
25
- */
26
- declare abstract class ThunderIDExpressClient<T = ThunderIDExpressConfig> extends LegacyThunderIDNodeClient<T> {
18
+ import { ThunderIDNodeClient, Storage, TokenResponse, User } from '@thunderid/node';
19
+ import express from 'express';
20
+ import { ExpressClientConfig } from './models/config';
21
+ declare class ThunderIDExpressClient<T extends ExpressClientConfig = ExpressClientConfig> extends ThunderIDNodeClient<T> {
22
+ private _expressConfig;
23
+ constructor();
24
+ initialize(config: T, storage?: Storage): Promise<boolean>;
25
+ get expressConfig(): ExpressClientConfig | undefined;
26
+ getUserFromRequest(req: express.Request): Promise<User | undefined>;
27
+ signIn(req: express.Request, res: express.Response, next: express.NextFunction, signInConfig?: Record<string, string | boolean>): Promise<TokenResponse>;
28
+ signOut(userId?: string): Promise<string>;
27
29
  }
28
30
  export default ThunderIDExpressClient;
29
31
  //# sourceMappingURL=ThunderIDExpressClient.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ThunderIDExpressClient.d.ts","sourceRoot":"","sources":["../src/ThunderIDExpressClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAC,yBAAyB,EAAC,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAC,sBAAsB,EAAC,MAAM,iBAAiB,CAAC;AAEvD;;;;;GAKG;AACH,uBAAe,sBAAsB,CAAC,CAAC,GAAG,sBAAsB,CAAE,SAAQ,yBAAyB,CAAC,CAAC,CAAC;CAAG;AAEzG,eAAe,sBAAsB,CAAC"}
1
+ {"version":3,"file":"ThunderIDExpressClient.d.ts","sourceRoot":"","sources":["../src/ThunderIDExpressClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAC,mBAAmB,EAA0B,OAAO,EAAE,aAAa,EAAE,IAAI,EAAC,MAAM,iBAAiB,CAAC;AAC1G,OAAO,OAAO,MAAM,SAAS,CAAC;AAG9B,OAAO,EAAC,mBAAmB,EAAC,MAAM,iBAAiB,CAAC;AAGpD,cAAM,sBAAsB,CAAC,CAAC,SAAS,mBAAmB,GAAG,mBAAmB,CAAE,SAAQ,mBAAmB,CAAC,CAAC,CAAC;IAC9G,OAAO,CAAC,cAAc,CAAkC;;IAMlC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAKhF,IAAW,aAAa,IAAI,mBAAmB,GAAG,SAAS,CAE1D;IAEY,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC;IAK1D,MAAM,CAC1B,GAAG,EAAE,OAAO,CAAC,OAAO,EACpB,GAAG,EAAE,OAAO,CAAC,QAAQ,EACrB,IAAI,EAAE,OAAO,CAAC,YAAY,EAC1B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAC9C,OAAO,CAAC,aAAa,CAAC;IAuDH,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAGhE;AAED,eAAe,sBAAsB,CAAC"}
@@ -25,12 +25,10 @@ let __thunderid_node = require("@thunderid/node");
25
25
  __thunderid_node = __toESM(__thunderid_node);
26
26
  let uuid = require("uuid");
27
27
  uuid = __toESM(uuid);
28
- let express = require("express");
29
- express = __toESM(express);
30
28
 
31
- //#region src/__legacy__/constants/default-options.ts
29
+ //#region src/constants/CookieConfig.ts
32
30
  /**
33
- * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com).
31
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
34
32
  *
35
33
  * WSO2 LLC. licenses this file to you under the Apache License,
36
34
  * Version 2.0 (the "License"); you may not use this file except
@@ -46,209 +44,345 @@ express = __toESM(express);
46
44
  * specific language governing permissions and limitations
47
45
  * under the License.
48
46
  */
49
- let CookieConfig = /* @__PURE__ */ function(CookieConfig$1) {
50
- CookieConfig$1[CookieConfig$1["defaultMaxAge"] = 9e4] = "defaultMaxAge";
51
- CookieConfig$1["defaultHttpOnly"] = "true";
52
- CookieConfig$1["defaultSameSite"] = "lax";
53
- CookieConfig$1["defaultSecure"] = "false";
54
- return CookieConfig$1;
55
- }({});
56
- const DEFAULT_LOGIN_PATH = "/login";
57
- const DEFAULT_LOGOUT_PATH = "/logout";
47
+ /** Session cookie name used across the Express SDK. */
48
+ const SESSION_COOKIE_NAME = "THUNDERID_SESSION_ID";
49
+ /** Default cookie configuration values. */
50
+ const CookieConfig = {
51
+ defaultExpirySeconds: 86400,
52
+ defaultHttpOnly: true,
53
+ defaultSameSite: "lax",
54
+ defaultSecure: false
55
+ };
56
+ var CookieConfig_default = CookieConfig;
58
57
 
59
58
  //#endregion
60
- //#region src/__legacy__/middleware/protect-route.ts
61
- const protectRoute = (thunderIDExpressClient, callback) => {
62
- return async (req, res, next) => {
63
- if (req.cookies.THUNDERID_SESSION_ID === void 0) {
64
- __thunderid_node.Logger.error("No session ID found in the request cookies");
65
- if (callback(res, "Unauthenticated")) return;
66
- return next();
67
- } else if (await thunderIDExpressClient.isSignedIn(req.cookies.THUNDERID_SESSION_ID)) return next();
68
- else {
69
- __thunderid_node.Logger.error("Invalid session ID found in the request cookies");
70
- if (callback(res, "Invalid session cookie")) return;
71
- return next();
72
- }
73
- };
59
+ //#region src/utils/expressUtils.ts
60
+ /**
61
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
62
+ *
63
+ * WSO2 LLC. licenses this file to you under the Apache License,
64
+ * Version 2.0 (the "License"); you may not use this file except
65
+ * in compliance with the License.
66
+ * You may obtain a copy of the License at
67
+ *
68
+ * http://www.apache.org/licenses/LICENSE-2.0
69
+ *
70
+ * Unless required by applicable law or agreed to in writing,
71
+ * software distributed under the License is distributed on an
72
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
73
+ * KIND, either express or implied. See the License for the
74
+ * specific language governing permissions and limitations
75
+ * under the License.
76
+ */
77
+ const AUTH_ERROR_REGEXP = /[?&]error=[^&]+/;
78
+ /**
79
+ * Returns `true` if the given URL contains an OAuth error query parameter.
80
+ *
81
+ * @param url - The URL to inspect.
82
+ */
83
+ const hasErrorInURL = (url) => AUTH_ERROR_REGEXP.test(url);
84
+ var expressUtils_default = hasErrorInURL;
85
+
86
+ //#endregion
87
+ //#region src/ThunderIDExpressClient.ts
88
+ var ThunderIDExpressClient = class extends __thunderid_node.ThunderIDNodeClient {
89
+ _expressConfig;
90
+ constructor() {
91
+ super();
92
+ }
93
+ async initialize(config, storage) {
94
+ this._expressConfig = config;
95
+ return super.initialize(config, storage);
96
+ }
97
+ get expressConfig() {
98
+ return this._expressConfig;
99
+ }
100
+ async getUserFromRequest(req) {
101
+ const sessionId = req.cookies?.[SESSION_COOKIE_NAME];
102
+ return this.getUser(sessionId);
103
+ }
104
+ async signIn(req, res, next, signInConfig) {
105
+ if (expressUtils_default(req.originalUrl)) return Promise.reject(new __thunderid_node.ThunderIDAuthException("EXPRESS-CLIENT-SI-IV01", "Invalid login request URL", "Login request contains an error query parameter in the URL"));
106
+ let userId = req.cookies?.[SESSION_COOKIE_NAME];
107
+ if (!userId) userId = (0, uuid.v4)();
108
+ const sc = this._expressConfig?.sessionCookie;
109
+ const authRedirectCallback = (url) => {
110
+ if (!url) return;
111
+ res.cookie(SESSION_COOKIE_NAME, userId, {
112
+ httpOnly: sc?.httpOnly ?? CookieConfig_default.defaultHttpOnly,
113
+ maxAge: (sc?.expiryTime ?? CookieConfig_default.defaultExpirySeconds) * 1e3,
114
+ sameSite: sc?.sameSite ?? CookieConfig_default.defaultSameSite,
115
+ secure: sc?.secure ?? CookieConfig_default.defaultSecure
116
+ });
117
+ res.redirect(url);
118
+ if (typeof next === "function") next();
119
+ };
120
+ const authResponse = await super.signIn(authRedirectCallback, userId, req.query.code, req.query.session_state, req.query.state, signInConfig);
121
+ if (authResponse.accessToken || authResponse.idToken) return authResponse;
122
+ return {
123
+ accessToken: "",
124
+ createdAt: 0,
125
+ expiresIn: "",
126
+ idToken: "",
127
+ refreshToken: "",
128
+ scope: "",
129
+ tokenType: ""
130
+ };
131
+ }
132
+ async signOut(userId) {
133
+ return super.signOut(userId);
134
+ }
74
135
  };
136
+ var ThunderIDExpressClient_default = ThunderIDExpressClient;
75
137
 
76
138
  //#endregion
77
- //#region src/__legacy__/middleware/authentication.ts
78
- const thunderIDExpressAuth = (thunderIDExpressClient, config, onSignIn, onSignOut, onError) => {
79
- const router = new express.default.Router();
80
- router.use(async (req, res, next) => {
81
- req.thunderIDAuth = thunderIDExpressClient;
82
- res.thunderIDAuth = thunderIDExpressClient;
139
+ //#region src/middleware/authentication.ts
140
+ /**
141
+ * Returns Express middleware that initialises the ThunderID client and attaches
142
+ * it to `req.thunderIDAuth` for use in route handlers and `protect()`.
143
+ *
144
+ * Unlike the old `thunderID()` router, this function does **not** mount any
145
+ * routes automatically. Register sign-in and sign-out handlers explicitly:
146
+ *
147
+ * ```ts
148
+ * app.use(thunderID(config));
149
+ * app.get('/login', handleSignIn());
150
+ * app.get('/logout', handleSignOut());
151
+ * ```
152
+ *
153
+ * @param config - ThunderID Express configuration.
154
+ */
155
+ const thunderID = (config) => {
156
+ const client = new ThunderIDExpressClient_default();
157
+ let initPromise;
158
+ const getInitPromise = (req) => {
159
+ if (initPromise === void 0) {
160
+ const origin = `${req.protocol}://${req.get("host")}`;
161
+ initPromise = client.initialize({
162
+ ...config,
163
+ afterSignInUrl: config.afterSignInUrl ?? `${origin}/login`,
164
+ afterSignOutUrl: config.afterSignOutUrl ?? `${origin}/logout`
165
+ });
166
+ }
167
+ return initPromise;
168
+ };
169
+ return async (req, res, next) => {
170
+ await getInitPromise(req);
171
+ req.thunderIDAuth = client;
172
+ res.thunderIDAuth = client;
83
173
  next();
84
- });
85
- router.get(config.loginPath || DEFAULT_LOGIN_PATH, async (req, res, next) => {
174
+ };
175
+ };
176
+ /**
177
+ * Returns an Express route handler for the sign-in path.
178
+ *
179
+ * - If the request has no `?code` query param, initiates the OAuth 2.0 redirect.
180
+ * - If the request has `?code`, exchanges the authorization code for tokens,
181
+ * sets the session cookie, and calls `onSignIn`.
182
+ *
183
+ * Must be used after `thunderID()` middleware so that `req.thunderIDAuth` is set.
184
+ *
185
+ * ```ts
186
+ * app.get('/login', handleSignIn());
187
+ * ```
188
+ */
189
+ const handleSignIn = () => {
190
+ return async (req, res, next) => {
191
+ const client = req.thunderIDAuth;
192
+ if (!client) {
193
+ __thunderid_node.logger.error("thunderID() middleware must be mounted before handleSignIn()");
194
+ res.status(500).end();
195
+ return;
196
+ }
197
+ const config = client.expressConfig;
198
+ const onSignIn = config?.onSignIn ?? ((r) => r.end());
199
+ const onError = config?.onError ?? ((r, e) => {
200
+ __thunderid_node.logger.error(e.message);
201
+ r.status(500).end();
202
+ });
86
203
  try {
87
- const response = await thunderIDExpressClient.signIn(req, res, next, config.signInConfig);
204
+ const response = await client.signIn(req, res, next, config?.signInOptions);
88
205
  if (response.accessToken || response.idToken) onSignIn(res, response);
89
206
  } catch (e) {
90
- __thunderid_node.Logger.error(e.message);
207
+ __thunderid_node.logger.error(e.message);
91
208
  onError(res, e);
92
209
  }
93
- });
94
- router.get(config.logoutPath || DEFAULT_LOGOUT_PATH, async (req, res, next) => {
210
+ };
211
+ };
212
+ /**
213
+ * Returns an Express route handler for the sign-out path.
214
+ *
215
+ * - Clears the session cookie and redirects to the identity provider's
216
+ * end-session endpoint.
217
+ * - When the identity provider redirects back with `?state=sign_out_success`,
218
+ * calls `onSignOut`.
219
+ *
220
+ * Must be used after `thunderID()` middleware so that `req.thunderIDAuth` is set.
221
+ *
222
+ * ```ts
223
+ * app.get('/logout', handleSignOut());
224
+ * ```
225
+ */
226
+ const handleSignOut = () => {
227
+ return async (req, res) => {
228
+ const client = req.thunderIDAuth;
229
+ if (!client) {
230
+ __thunderid_node.logger.error("thunderID() middleware must be mounted before handleSignOut()");
231
+ res.status(500).end();
232
+ return;
233
+ }
234
+ const config = client.expressConfig;
235
+ const onSignOut = config?.onSignOut ?? ((r) => r.end());
236
+ const onError = config?.onError ?? ((r, e) => {
237
+ __thunderid_node.logger.error(e.message);
238
+ r.status(500).end();
239
+ });
95
240
  if (req.query.state === "sign_out_success") {
96
241
  onSignOut(res);
97
242
  return;
98
243
  }
99
- if (req.cookies.THUNDERID_SESSION_ID === void 0) {
100
- onError(res, new __thunderid_node.ThunderIDAuthException("EXPRESS-AUTH_MW-LOGOUT-NF01", "No cookie found in the request", "No cookie was sent with the request. The user may not have signed in yet."));
244
+ const sessionId = req.cookies?.[SESSION_COOKIE_NAME];
245
+ if (!sessionId) {
246
+ onError(res, new __thunderid_node.ThunderIDRuntimeError("No cookie found in the request", "EXPRESS-AUTH_MW-LOGOUT-NF01", "express"));
101
247
  return;
102
- } else try {
103
- const signOutURL = await req.thunderIDAuth.signOut(req.cookies.THUNDERID_SESSION_ID);
248
+ }
249
+ try {
250
+ const signOutURL = await client.signOut(sessionId);
104
251
  if (signOutURL) {
105
- res.cookie("THUNDERID_SESSION_ID", null, { maxAge: 0 });
252
+ res.cookie(SESSION_COOKIE_NAME, null, { maxAge: 0 });
106
253
  res.redirect(signOutURL);
107
- return;
108
254
  }
109
255
  } catch (e) {
110
256
  onError(res, e);
111
- return;
112
257
  }
113
- });
114
- return router;
258
+ };
115
259
  };
116
260
 
117
261
  //#endregion
118
- //#region src/__legacy__/utils/express-utils.ts
119
- var ExpressUtils = class {
120
- static AUTH_CODE_REGEXP = /[?&]error=[^&]+/;
121
- /**
122
- * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com).
123
- *
124
- * WSO2 LLC. licenses this file to you under the Apache License,
125
- * Version 2.0 (the "License"); you may not use this file except
126
- * in compliance with the License.
127
- * You may obtain a copy of the License at
128
- *
129
- * http://www.apache.org/licenses/LICENSE-2.0
130
- *
131
- * Unless required by applicable law or agreed to in writing,
132
- * software distributed under the License is distributed on an
133
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
134
- * KIND, either express or implied. See the License for the
135
- * specific language governing permissions and limitations
136
- * under the License.
137
- */
138
- static hasErrorInURL(url) {
139
- return this.AUTH_CODE_REGEXP.test(url);
140
- }
262
+ //#region src/middleware/protect.ts
263
+ /**
264
+ * Returns Express middleware that blocks unauthenticated requests.
265
+ * Requires `thunderID()` to be mounted before this middleware so that
266
+ * `req.thunderIDAuth` is populated.
267
+ *
268
+ * @param onUnauthenticated - Called when the session is missing or invalid.
269
+ * Defaults to sending a 401 response.
270
+ */
271
+ const protect = (onUnauthenticated) => {
272
+ return async (req, res, next) => {
273
+ const client = req.thunderIDAuth;
274
+ const sessionId = req.cookies?.[SESSION_COOKIE_NAME];
275
+ const reject = () => {
276
+ if (onUnauthenticated) onUnauthenticated(res);
277
+ else res.status(401).end();
278
+ };
279
+ if (!client || !sessionId) {
280
+ __thunderid_node.logger.error("No session ID found in the request cookies");
281
+ reject();
282
+ return;
283
+ }
284
+ if (await client.isSignedIn(sessionId)) return next();
285
+ __thunderid_node.logger.error("Invalid session ID found in the request cookies");
286
+ reject();
287
+ };
141
288
  };
289
+ var protect_default = protect;
142
290
 
143
291
  //#endregion
144
- //#region src/__legacy__/client.ts
145
- var ThunderIDExpressClient = class ThunderIDExpressClient {
146
- _authClient;
147
- _storage;
148
- static _clientConfig;
149
- static _instance;
150
- constructor(config, storage) {
151
- ThunderIDExpressClient._clientConfig = { ...config };
152
- const nodeClientConfig = {
153
- ...config,
154
- afterSignInUrl: config.appURL + (config.loginPath || DEFAULT_LOGIN_PATH),
155
- afterSignOutUrl: config.appURL + (config.logoutPath || DEFAULT_LOGOUT_PATH)
156
- };
157
- if (storage) {
158
- __thunderid_node.Logger.debug("Initializing user provided storage");
159
- this._storage = storage;
292
+ //#region src/middleware/flow.ts
293
+ /**
294
+ * Returns an Express route handler that drives the embedded sign-in flow loop.
295
+ *
296
+ * Requires `thunderID()` middleware with `mode: 'embedded'` to be mounted first.
297
+ * On each POST, the handler advances the flow one step and returns JSON.
298
+ *
299
+ * **First call** — no `executionId`:
300
+ * ```json
301
+ * { "applicationId": "app-id", "flowType": "SIGN_IN" }
302
+ * ```
303
+ * Response includes `executionId`, `challengeToken`, `authId`, and `components`
304
+ * (the UI elements to render).
305
+ *
306
+ * **Subsequent calls** — continue the flow:
307
+ * ```json
308
+ * { "executionId": "...", "challengeToken": "...", "authId": "...", "inputs": { ... } }
309
+ * ```
310
+ *
311
+ * **On completion** — flow returns `{ "done": true, "redirectUrl": "/login?code=..." }`.
312
+ * The client navigates to `redirectUrl`, which is handled by `handleSignIn()` to
313
+ * exchange the code and set the session cookie.
314
+ *
315
+ * ```ts
316
+ * app.use(thunderID({ ..., mode: 'embedded' }));
317
+ * app.get('/login', handleSignIn());
318
+ * app.post('/flow/sign-in', handleFlow());
319
+ * app.get('/logout', handleSignOut());
320
+ * ```
321
+ */
322
+ const handleFlow = () => {
323
+ return async (req, res) => {
324
+ const client = req.thunderIDAuth;
325
+ if (!client) {
326
+ __thunderid_node.logger.error("thunderID() middleware must be mounted before handleFlow()");
327
+ res.status(500).json({ error: "SDK not initialised" });
328
+ return;
160
329
  }
161
- this._authClient = new __thunderid_node.LegacyThunderIDNodeClient();
162
- this._authClient.initialize(nodeClientConfig, this._storage);
163
- }
164
- static getInstance(config, storage) {
165
- if (!ThunderIDExpressClient._instance && config) {
166
- ThunderIDExpressClient._instance = new ThunderIDExpressClient(config, storage);
167
- __thunderid_node.Logger.debug("Initialized ThunderIDExpressClient successfully");
330
+ const baseUrl = client.expressConfig?.baseUrl;
331
+ if (!baseUrl) {
332
+ res.status(500).json({ error: "baseUrl is not configured" });
333
+ return;
168
334
  }
169
- if (!ThunderIDExpressClient._instance && !config) throw Error(new __thunderid_node.ThunderIDAuthException("EXPRESS-CLIENT-GI1-NF01", "User configuration is not found", "User config has not been passed to initialize ThunderIDExpressClient").toString());
170
- return ThunderIDExpressClient._instance;
171
- }
172
- async signIn(req, res, next, signInConfig) {
173
- if (ExpressUtils.hasErrorInURL(req.originalUrl)) return Promise.reject(new __thunderid_node.ThunderIDAuthException("EXPRESS-CLIENT-SI-IV01", "Invalid login request URL", "Login request contains an error query parameter in the URL"));
174
- let userId = req.cookies.THUNDERID_SESSION_ID;
175
- if (!userId) userId = (0, uuid.v4)();
176
- const authRedirectCallback = (url) => {
177
- if (url) {
178
- __thunderid_node.Logger.debug("Redirecting to: " + url);
179
- res.cookie("THUNDERID_SESSION_ID", userId, {
180
- maxAge: ThunderIDExpressClient._clientConfig.cookieConfig?.maxAge ? ThunderIDExpressClient._clientConfig.cookieConfig.maxAge : CookieConfig.defaultMaxAge,
181
- httpOnly: ThunderIDExpressClient._clientConfig.cookieConfig?.httpOnly ?? CookieConfig.defaultHttpOnly,
182
- sameSite: ThunderIDExpressClient._clientConfig.cookieConfig?.sameSite ?? CookieConfig.defaultSameSite,
183
- secure: ThunderIDExpressClient._clientConfig.cookieConfig?.secure ?? CookieConfig.defaultSecure
335
+ const { applicationId, flowType, executionId, challengeToken, authId, inputs } = req.body ?? {};
336
+ try {
337
+ let resolvedAuthId = authId;
338
+ if (!executionId && !resolvedAuthId) {
339
+ const authUrl = await client.getSignInUrl();
340
+ resolvedAuthId = new URL(authUrl).searchParams.get("authId") ?? void 0;
341
+ }
342
+ const flowResponse = await (0, __thunderid_node.executeEmbeddedSignInFlowV2)({
343
+ authId: resolvedAuthId,
344
+ baseUrl,
345
+ payload: executionId ? {
346
+ action: "submit",
347
+ challengeToken,
348
+ executionId,
349
+ inputs
350
+ } : {
351
+ applicationId,
352
+ flowType: flowType ?? "SIGN_IN"
353
+ }
354
+ });
355
+ if (flowResponse.redirectUrl) {
356
+ res.json({
357
+ done: true,
358
+ redirectUrl: flowResponse.redirectUrl
184
359
  });
185
- res.redirect(url);
186
- next && typeof next === "function" && next();
360
+ return;
187
361
  }
188
- };
189
- const authResponse = await this._authClient.signIn(authRedirectCallback, userId, req.query.code, req.query.session_state, req.query.state, signInConfig);
190
- if (authResponse.accessToken || authResponse.idToken) return authResponse;
191
- else return {
192
- accessToken: "",
193
- createdAt: 0,
194
- expiresIn: "",
195
- idToken: "",
196
- refreshToken: "",
197
- scope: "",
198
- tokenType: ""
199
- };
200
- }
201
- async signOut(userId) {
202
- return this._authClient.signOut(userId);
203
- }
204
- async isSignedIn(userId) {
205
- return this._authClient.isSignedIn(userId);
206
- }
207
- async getIdToken(userId) {
208
- return this._authClient.getIdToken(userId);
209
- }
210
- async getUser(userId) {
211
- return this._authClient.getUser(userId);
212
- }
213
- async getOpenIDProviderEndpoints() {
214
- return this._authClient.getOpenIDProviderEndpoints();
215
- }
216
- async getDecodedIdToken(userId) {
217
- return this._authClient.getDecodedIdToken(userId);
218
- }
219
- async getAccessToken(userId) {
220
- return this._authClient.getAccessToken(userId);
221
- }
222
- async exchangeToken(config, userId) {
223
- return this._authClient.exchangeToken(config, userId);
224
- }
225
- async reInitialize(config) {
226
- return this._authClient.reInitialize(config);
227
- }
228
- async revokeAccessToken(userId) {
229
- return this._authClient.revokeAccessToken(userId);
230
- }
231
- static didSignOutFail(afterSignOutUrl) {
232
- return __thunderid_node.LegacyThunderIDNodeClient.didSignOutFail(afterSignOutUrl);
233
- }
234
- static isSignOutSuccessful(afterSignOutUrl) {
235
- return __thunderid_node.LegacyThunderIDNodeClient.isSignOutSuccessful(afterSignOutUrl);
236
- }
237
- static protectRoute(callback) {
238
- if (!this._instance) throw new __thunderid_node.ThunderIDAuthException("EXPRESS-CLIENT-PR-NF01", "ThunderIDExpressClient is not instantiated", "Create an instance of ThunderIDExpressClient before using calling this method.");
239
- return protectRoute(this._instance, callback);
240
- }
241
- static thunderIDExpressAuth(onSignIn, onSignOut, onError) {
242
- if (!this._instance) throw new __thunderid_node.ThunderIDAuthException("EXPRESS-CLIENT-AEA-NF01", "ThunderIDExpressClient is not instantiated", "Create an instance of ThunderIDExpressClient before using calling this method.");
243
- return thunderIDExpressAuth(this._instance, ThunderIDExpressClient._clientConfig, onSignIn, onSignOut, onError);
244
- }
245
- async getStorageManager() {
246
- return this._authClient.getStorageManager();
247
- }
362
+ res.json({
363
+ authId: resolvedAuthId,
364
+ challengeToken: flowResponse.challengeToken,
365
+ components: flowResponse.data?.meta?.components ?? [],
366
+ executionId: flowResponse.executionId,
367
+ flowStatus: flowResponse.flowStatus
368
+ });
369
+ } catch (e) {
370
+ __thunderid_node.logger.error(e.message);
371
+ res.status(500).json({ error: e.message ?? "Flow execution failed" });
372
+ }
373
+ };
248
374
  };
375
+ var flow_default = handleFlow;
249
376
 
250
377
  //#endregion
251
- exports.ThunderIDExpressClient = ThunderIDExpressClient;
378
+ exports.CookieConfig = CookieConfig_default;
379
+ exports.SESSION_COOKIE_NAME = SESSION_COOKIE_NAME;
380
+ exports.ThunderIDExpressClient = ThunderIDExpressClient_default;
381
+ exports.handleFlow = flow_default;
382
+ exports.handleSignIn = handleSignIn;
383
+ exports.handleSignOut = handleSignOut;
384
+ exports.protect = protect_default;
385
+ exports.thunderID = thunderID;
252
386
  Object.keys(__thunderid_node).forEach(function (k) {
253
387
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
254
388
  enumerable: true,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com).
2
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
3
3
  *
4
4
  * WSO2 LLC. licenses this file to you under the Apache License,
5
5
  * Version 2.0 (the "License"); you may not use this file except
@@ -15,14 +15,14 @@
15
15
  * specific language governing permissions and limitations
16
16
  * under the License.
17
17
  */
18
- export declare const LOGGER_CONFIG: {
19
- bgGreen: string;
20
- bgRed: string;
21
- bgYellow: string;
22
- fgBlack: string;
23
- fgGreen: string;
24
- fgRed: string;
25
- fgYellow: string;
26
- reset: string;
18
+ /** Session cookie name used across the Express SDK. */
19
+ export declare const SESSION_COOKIE_NAME = "THUNDERID_SESSION_ID";
20
+ /** Default cookie configuration values. */
21
+ declare const CookieConfig: {
22
+ defaultExpirySeconds: number;
23
+ defaultHttpOnly: boolean;
24
+ defaultSameSite: "lax";
25
+ defaultSecure: boolean;
27
26
  };
28
- //# sourceMappingURL=logger-config.d.ts.map
27
+ export default CookieConfig;
28
+ //# sourceMappingURL=CookieConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CookieConfig.d.ts","sourceRoot":"","sources":["../../src/constants/CookieConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,uDAAuD;AACvD,eAAO,MAAM,mBAAmB,yBAAyB,CAAC;AAE1D,2CAA2C;AAC3C,QAAA,MAAM,YAAY;;;;;CAKjB,CAAC;AAEF,eAAe,YAAY,CAAC"}