@thunderid/express 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ThunderIDExpressClient.d.ts +11 -9
- package/dist/ThunderIDExpressClient.d.ts.map +1 -1
- package/dist/cjs/index.cjs +306 -172
- package/dist/{__legacy__/constants/logger-config.d.ts → constants/CookieConfig.d.ts} +11 -11
- package/dist/constants/CookieConfig.d.ts.map +1 -0
- package/dist/edge/index.js +300 -172
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +300 -172
- package/dist/middleware/authentication.d.ts +66 -0
- package/dist/middleware/authentication.d.ts.map +1 -0
- package/dist/middleware/flow.d.ts +50 -0
- package/dist/middleware/flow.d.ts.map +1 -0
- package/dist/{__legacy__/middleware/protect-route.d.ts → middleware/protect.d.ts} +12 -5
- package/dist/middleware/protect.d.ts.map +1 -0
- package/dist/models/config.d.ts +28 -9
- package/dist/models/config.d.ts.map +1 -1
- package/dist/{__legacy__/models/protect-route.d.ts → models/protectRoute.d.ts} +6 -3
- package/dist/models/protectRoute.d.ts.map +1 -0
- package/dist/{__legacy__/constants/index.d.ts → utils/expressUtils.d.ts} +9 -4
- package/dist/utils/expressUtils.d.ts.map +1 -0
- package/package.json +2 -2
- package/dist/__legacy__/client.d.ts +0 -46
- package/dist/__legacy__/client.d.ts.map +0 -1
- package/dist/__legacy__/constants/default-options.d.ts +0 -26
- package/dist/__legacy__/constants/default-options.d.ts.map +0 -1
- package/dist/__legacy__/constants/index.d.ts.map +0 -1
- package/dist/__legacy__/constants/logger-config.d.ts.map +0 -1
- package/dist/__legacy__/middleware/authentication.d.ts +0 -23
- package/dist/__legacy__/middleware/authentication.d.ts.map +0 -1
- package/dist/__legacy__/middleware/index.d.ts +0 -20
- package/dist/__legacy__/middleware/index.d.ts.map +0 -1
- package/dist/__legacy__/middleware/protect-route.d.ts.map +0 -1
- package/dist/__legacy__/models/client-config.d.ts +0 -33
- package/dist/__legacy__/models/client-config.d.ts.map +0 -1
- package/dist/__legacy__/models/data.d.ts +0 -21
- package/dist/__legacy__/models/data.d.ts.map +0 -1
- package/dist/__legacy__/models/index.d.ts +0 -21
- package/dist/__legacy__/models/index.d.ts.map +0 -1
- package/dist/__legacy__/models/protect-route.d.ts.map +0 -1
- package/dist/__legacy__/utils/express-utils.d.ts +0 -22
- package/dist/__legacy__/utils/express-utils.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ThunderIDAuthException, ThunderIDNodeClient, ThunderIDRuntimeError, executeEmbeddedSignInFlowV2, logger } from "@thunderid/node";
|
|
2
2
|
import { v4 } from "uuid";
|
|
3
|
-
import express from "express";
|
|
4
3
|
|
|
5
4
|
export * from "@thunderid/node"
|
|
6
5
|
|
|
7
|
-
//#region src/
|
|
6
|
+
//#region src/constants/CookieConfig.ts
|
|
8
7
|
/**
|
|
9
|
-
* Copyright (c)
|
|
8
|
+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
|
|
10
9
|
*
|
|
11
10
|
* WSO2 LLC. licenses this file to you under the Apache License,
|
|
12
11
|
* Version 2.0 (the "License"); you may not use this file except
|
|
@@ -22,206 +21,335 @@ export * from "@thunderid/node"
|
|
|
22
21
|
* specific language governing permissions and limitations
|
|
23
22
|
* under the License.
|
|
24
23
|
*/
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
24
|
+
/** Session cookie name used across the Express SDK. */
|
|
25
|
+
const SESSION_COOKIE_NAME = "THUNDERID_SESSION_ID";
|
|
26
|
+
/** Default cookie configuration values. */
|
|
27
|
+
const CookieConfig = {
|
|
28
|
+
defaultExpirySeconds: 86400,
|
|
29
|
+
defaultHttpOnly: true,
|
|
30
|
+
defaultSameSite: "lax",
|
|
31
|
+
defaultSecure: false
|
|
32
|
+
};
|
|
33
|
+
var CookieConfig_default = CookieConfig;
|
|
34
34
|
|
|
35
35
|
//#endregion
|
|
36
|
-
//#region src/
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
36
|
+
//#region src/utils/expressUtils.ts
|
|
37
|
+
/**
|
|
38
|
+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
|
|
39
|
+
*
|
|
40
|
+
* WSO2 LLC. licenses this file to you under the Apache License,
|
|
41
|
+
* Version 2.0 (the "License"); you may not use this file except
|
|
42
|
+
* in compliance with the License.
|
|
43
|
+
* You may obtain a copy of the License at
|
|
44
|
+
*
|
|
45
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
46
|
+
*
|
|
47
|
+
* Unless required by applicable law or agreed to in writing,
|
|
48
|
+
* software distributed under the License is distributed on an
|
|
49
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
50
|
+
* KIND, either express or implied. See the License for the
|
|
51
|
+
* specific language governing permissions and limitations
|
|
52
|
+
* under the License.
|
|
53
|
+
*/
|
|
54
|
+
const AUTH_ERROR_REGEXP = /[?&]error=[^&]+/;
|
|
55
|
+
/**
|
|
56
|
+
* Returns `true` if the given URL contains an OAuth error query parameter.
|
|
57
|
+
*
|
|
58
|
+
* @param url - The URL to inspect.
|
|
59
|
+
*/
|
|
60
|
+
const hasErrorInURL = (url) => AUTH_ERROR_REGEXP.test(url);
|
|
61
|
+
var expressUtils_default = hasErrorInURL;
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/ThunderIDExpressClient.ts
|
|
65
|
+
var ThunderIDExpressClient = class extends ThunderIDNodeClient {
|
|
66
|
+
_expressConfig;
|
|
67
|
+
constructor() {
|
|
68
|
+
super();
|
|
69
|
+
}
|
|
70
|
+
async initialize(config, storage) {
|
|
71
|
+
this._expressConfig = config;
|
|
72
|
+
return super.initialize(config, storage);
|
|
73
|
+
}
|
|
74
|
+
get expressConfig() {
|
|
75
|
+
return this._expressConfig;
|
|
76
|
+
}
|
|
77
|
+
async getUserFromRequest(req) {
|
|
78
|
+
const sessionId = req.cookies?.[SESSION_COOKIE_NAME];
|
|
79
|
+
return this.getUser(sessionId);
|
|
80
|
+
}
|
|
81
|
+
async signIn(req, res, next, signInConfig) {
|
|
82
|
+
if (expressUtils_default(req.originalUrl)) return Promise.reject(new ThunderIDAuthException("EXPRESS-CLIENT-SI-IV01", "Invalid login request URL", "Login request contains an error query parameter in the URL"));
|
|
83
|
+
let userId = req.cookies?.[SESSION_COOKIE_NAME];
|
|
84
|
+
if (!userId) userId = v4();
|
|
85
|
+
const sc = this._expressConfig?.sessionCookie;
|
|
86
|
+
const authRedirectCallback = (url) => {
|
|
87
|
+
if (!url) return;
|
|
88
|
+
res.cookie(SESSION_COOKIE_NAME, userId, {
|
|
89
|
+
httpOnly: sc?.httpOnly ?? CookieConfig_default.defaultHttpOnly,
|
|
90
|
+
maxAge: (sc?.expiryTime ?? CookieConfig_default.defaultExpirySeconds) * 1e3,
|
|
91
|
+
sameSite: sc?.sameSite ?? CookieConfig_default.defaultSameSite,
|
|
92
|
+
secure: sc?.secure ?? CookieConfig_default.defaultSecure
|
|
93
|
+
});
|
|
94
|
+
res.redirect(url);
|
|
95
|
+
if (typeof next === "function") next();
|
|
96
|
+
};
|
|
97
|
+
const authResponse = await super.signIn(authRedirectCallback, userId, req.query.code, req.query.session_state, req.query.state, signInConfig);
|
|
98
|
+
if (authResponse.accessToken || authResponse.idToken) return authResponse;
|
|
99
|
+
return {
|
|
100
|
+
accessToken: "",
|
|
101
|
+
createdAt: 0,
|
|
102
|
+
expiresIn: "",
|
|
103
|
+
idToken: "",
|
|
104
|
+
refreshToken: "",
|
|
105
|
+
scope: "",
|
|
106
|
+
tokenType: ""
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
async signOut(userId) {
|
|
110
|
+
return super.signOut(userId);
|
|
111
|
+
}
|
|
50
112
|
};
|
|
113
|
+
var ThunderIDExpressClient_default = ThunderIDExpressClient;
|
|
51
114
|
|
|
52
115
|
//#endregion
|
|
53
|
-
//#region src/
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
116
|
+
//#region src/middleware/authentication.ts
|
|
117
|
+
/**
|
|
118
|
+
* Returns Express middleware that initialises the ThunderID client and attaches
|
|
119
|
+
* it to `req.thunderIDAuth` for use in route handlers and `protect()`.
|
|
120
|
+
*
|
|
121
|
+
* Unlike the old `thunderID()` router, this function does **not** mount any
|
|
122
|
+
* routes automatically. Register sign-in and sign-out handlers explicitly:
|
|
123
|
+
*
|
|
124
|
+
* ```ts
|
|
125
|
+
* app.use(thunderID(config));
|
|
126
|
+
* app.get('/login', handleSignIn());
|
|
127
|
+
* app.get('/logout', handleSignOut());
|
|
128
|
+
* ```
|
|
129
|
+
*
|
|
130
|
+
* @param config - ThunderID Express configuration.
|
|
131
|
+
*/
|
|
132
|
+
const thunderID = (config) => {
|
|
133
|
+
const client = new ThunderIDExpressClient_default();
|
|
134
|
+
let initPromise;
|
|
135
|
+
const getInitPromise = (req) => {
|
|
136
|
+
if (initPromise === void 0) {
|
|
137
|
+
const origin = `${req.protocol}://${req.get("host")}`;
|
|
138
|
+
initPromise = client.initialize({
|
|
139
|
+
...config,
|
|
140
|
+
afterSignInUrl: config.afterSignInUrl ?? `${origin}/login`,
|
|
141
|
+
afterSignOutUrl: config.afterSignOutUrl ?? `${origin}/logout`
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
return initPromise;
|
|
145
|
+
};
|
|
146
|
+
return async (req, res, next) => {
|
|
147
|
+
await getInitPromise(req);
|
|
148
|
+
req.thunderIDAuth = client;
|
|
149
|
+
res.thunderIDAuth = client;
|
|
59
150
|
next();
|
|
60
|
-
}
|
|
61
|
-
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Returns an Express route handler for the sign-in path.
|
|
155
|
+
*
|
|
156
|
+
* - If the request has no `?code` query param, initiates the OAuth 2.0 redirect.
|
|
157
|
+
* - If the request has `?code`, exchanges the authorization code for tokens,
|
|
158
|
+
* sets the session cookie, and calls `onSignIn`.
|
|
159
|
+
*
|
|
160
|
+
* Must be used after `thunderID()` middleware so that `req.thunderIDAuth` is set.
|
|
161
|
+
*
|
|
162
|
+
* ```ts
|
|
163
|
+
* app.get('/login', handleSignIn());
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
const handleSignIn = () => {
|
|
167
|
+
return async (req, res, next) => {
|
|
168
|
+
const client = req.thunderIDAuth;
|
|
169
|
+
if (!client) {
|
|
170
|
+
logger.error("thunderID() middleware must be mounted before handleSignIn()");
|
|
171
|
+
res.status(500).end();
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const config = client.expressConfig;
|
|
175
|
+
const onSignIn = config?.onSignIn ?? ((r) => r.end());
|
|
176
|
+
const onError = config?.onError ?? ((r, e) => {
|
|
177
|
+
logger.error(e.message);
|
|
178
|
+
r.status(500).end();
|
|
179
|
+
});
|
|
62
180
|
try {
|
|
63
|
-
const response = await
|
|
181
|
+
const response = await client.signIn(req, res, next, config?.signInOptions);
|
|
64
182
|
if (response.accessToken || response.idToken) onSignIn(res, response);
|
|
65
183
|
} catch (e) {
|
|
66
|
-
|
|
184
|
+
logger.error(e.message);
|
|
67
185
|
onError(res, e);
|
|
68
186
|
}
|
|
69
|
-
}
|
|
70
|
-
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
/**
|
|
190
|
+
* Returns an Express route handler for the sign-out path.
|
|
191
|
+
*
|
|
192
|
+
* - Clears the session cookie and redirects to the identity provider's
|
|
193
|
+
* end-session endpoint.
|
|
194
|
+
* - When the identity provider redirects back with `?state=sign_out_success`,
|
|
195
|
+
* calls `onSignOut`.
|
|
196
|
+
*
|
|
197
|
+
* Must be used after `thunderID()` middleware so that `req.thunderIDAuth` is set.
|
|
198
|
+
*
|
|
199
|
+
* ```ts
|
|
200
|
+
* app.get('/logout', handleSignOut());
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
const handleSignOut = () => {
|
|
204
|
+
return async (req, res) => {
|
|
205
|
+
const client = req.thunderIDAuth;
|
|
206
|
+
if (!client) {
|
|
207
|
+
logger.error("thunderID() middleware must be mounted before handleSignOut()");
|
|
208
|
+
res.status(500).end();
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const config = client.expressConfig;
|
|
212
|
+
const onSignOut = config?.onSignOut ?? ((r) => r.end());
|
|
213
|
+
const onError = config?.onError ?? ((r, e) => {
|
|
214
|
+
logger.error(e.message);
|
|
215
|
+
r.status(500).end();
|
|
216
|
+
});
|
|
71
217
|
if (req.query.state === "sign_out_success") {
|
|
72
218
|
onSignOut(res);
|
|
73
219
|
return;
|
|
74
220
|
}
|
|
75
|
-
|
|
76
|
-
|
|
221
|
+
const sessionId = req.cookies?.[SESSION_COOKIE_NAME];
|
|
222
|
+
if (!sessionId) {
|
|
223
|
+
onError(res, new ThunderIDRuntimeError("No cookie found in the request", "EXPRESS-AUTH_MW-LOGOUT-NF01", "express"));
|
|
77
224
|
return;
|
|
78
|
-
}
|
|
79
|
-
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
const signOutURL = await client.signOut(sessionId);
|
|
80
228
|
if (signOutURL) {
|
|
81
|
-
res.cookie(
|
|
229
|
+
res.cookie(SESSION_COOKIE_NAME, null, { maxAge: 0 });
|
|
82
230
|
res.redirect(signOutURL);
|
|
83
|
-
return;
|
|
84
231
|
}
|
|
85
232
|
} catch (e) {
|
|
86
233
|
onError(res, e);
|
|
87
|
-
return;
|
|
88
234
|
}
|
|
89
|
-
}
|
|
90
|
-
return router;
|
|
235
|
+
};
|
|
91
236
|
};
|
|
92
237
|
|
|
93
238
|
//#endregion
|
|
94
|
-
//#region src/
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
239
|
+
//#region src/middleware/protect.ts
|
|
240
|
+
/**
|
|
241
|
+
* Returns Express middleware that blocks unauthenticated requests.
|
|
242
|
+
* Requires `thunderID()` to be mounted before this middleware so that
|
|
243
|
+
* `req.thunderIDAuth` is populated.
|
|
244
|
+
*
|
|
245
|
+
* @param onUnauthenticated - Called when the session is missing or invalid.
|
|
246
|
+
* Defaults to sending a 401 response.
|
|
247
|
+
*/
|
|
248
|
+
const protect = (onUnauthenticated) => {
|
|
249
|
+
return async (req, res, next) => {
|
|
250
|
+
const client = req.thunderIDAuth;
|
|
251
|
+
const sessionId = req.cookies?.[SESSION_COOKIE_NAME];
|
|
252
|
+
const reject = () => {
|
|
253
|
+
if (onUnauthenticated) onUnauthenticated(res);
|
|
254
|
+
else res.status(401).end();
|
|
255
|
+
};
|
|
256
|
+
if (!client || !sessionId) {
|
|
257
|
+
logger.error("No session ID found in the request cookies");
|
|
258
|
+
reject();
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
if (await client.isSignedIn(sessionId)) return next();
|
|
262
|
+
logger.error("Invalid session ID found in the request cookies");
|
|
263
|
+
reject();
|
|
264
|
+
};
|
|
117
265
|
};
|
|
266
|
+
var protect_default = protect;
|
|
118
267
|
|
|
119
268
|
//#endregion
|
|
120
|
-
//#region src/
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
269
|
+
//#region src/middleware/flow.ts
|
|
270
|
+
/**
|
|
271
|
+
* Returns an Express route handler that drives the embedded sign-in flow loop.
|
|
272
|
+
*
|
|
273
|
+
* Requires `thunderID()` middleware with `mode: 'embedded'` to be mounted first.
|
|
274
|
+
* On each POST, the handler advances the flow one step and returns JSON.
|
|
275
|
+
*
|
|
276
|
+
* **First call** — no `executionId`:
|
|
277
|
+
* ```json
|
|
278
|
+
* { "applicationId": "app-id", "flowType": "SIGN_IN" }
|
|
279
|
+
* ```
|
|
280
|
+
* Response includes `executionId`, `challengeToken`, `authId`, and `components`
|
|
281
|
+
* (the UI elements to render).
|
|
282
|
+
*
|
|
283
|
+
* **Subsequent calls** — continue the flow:
|
|
284
|
+
* ```json
|
|
285
|
+
* { "executionId": "...", "challengeToken": "...", "authId": "...", "inputs": { ... } }
|
|
286
|
+
* ```
|
|
287
|
+
*
|
|
288
|
+
* **On completion** — flow returns `{ "done": true, "redirectUrl": "/login?code=..." }`.
|
|
289
|
+
* The client navigates to `redirectUrl`, which is handled by `handleSignIn()` to
|
|
290
|
+
* exchange the code and set the session cookie.
|
|
291
|
+
*
|
|
292
|
+
* ```ts
|
|
293
|
+
* app.use(thunderID({ ..., mode: 'embedded' }));
|
|
294
|
+
* app.get('/login', handleSignIn());
|
|
295
|
+
* app.post('/flow/sign-in', handleFlow());
|
|
296
|
+
* app.get('/logout', handleSignOut());
|
|
297
|
+
* ```
|
|
298
|
+
*/
|
|
299
|
+
const handleFlow = () => {
|
|
300
|
+
return async (req, res) => {
|
|
301
|
+
const client = req.thunderIDAuth;
|
|
302
|
+
if (!client) {
|
|
303
|
+
logger.error("thunderID() middleware must be mounted before handleFlow()");
|
|
304
|
+
res.status(500).json({ error: "SDK not initialised" });
|
|
305
|
+
return;
|
|
136
306
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (!ThunderIDExpressClient._instance && config) {
|
|
142
|
-
ThunderIDExpressClient._instance = new ThunderIDExpressClient(config, storage);
|
|
143
|
-
Logger.debug("Initialized ThunderIDExpressClient successfully");
|
|
307
|
+
const baseUrl = client.expressConfig?.baseUrl;
|
|
308
|
+
if (!baseUrl) {
|
|
309
|
+
res.status(500).json({ error: "baseUrl is not configured" });
|
|
310
|
+
return;
|
|
144
311
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
312
|
+
const { applicationId, flowType, executionId, challengeToken, authId, inputs } = req.body ?? {};
|
|
313
|
+
try {
|
|
314
|
+
let resolvedAuthId = authId;
|
|
315
|
+
if (!executionId && !resolvedAuthId) {
|
|
316
|
+
const authUrl = await client.getSignInUrl();
|
|
317
|
+
resolvedAuthId = new URL(authUrl).searchParams.get("authId") ?? void 0;
|
|
318
|
+
}
|
|
319
|
+
const flowResponse = await executeEmbeddedSignInFlowV2({
|
|
320
|
+
authId: resolvedAuthId,
|
|
321
|
+
baseUrl,
|
|
322
|
+
payload: executionId ? {
|
|
323
|
+
action: "submit",
|
|
324
|
+
challengeToken,
|
|
325
|
+
executionId,
|
|
326
|
+
inputs
|
|
327
|
+
} : {
|
|
328
|
+
applicationId,
|
|
329
|
+
flowType: flowType ?? "SIGN_IN"
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
if (flowResponse.redirectUrl) {
|
|
333
|
+
res.json({
|
|
334
|
+
done: true,
|
|
335
|
+
redirectUrl: flowResponse.redirectUrl
|
|
160
336
|
});
|
|
161
|
-
|
|
162
|
-
next && typeof next === "function" && next();
|
|
337
|
+
return;
|
|
163
338
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
async signOut(userId) {
|
|
178
|
-
return this._authClient.signOut(userId);
|
|
179
|
-
}
|
|
180
|
-
async isSignedIn(userId) {
|
|
181
|
-
return this._authClient.isSignedIn(userId);
|
|
182
|
-
}
|
|
183
|
-
async getIdToken(userId) {
|
|
184
|
-
return this._authClient.getIdToken(userId);
|
|
185
|
-
}
|
|
186
|
-
async getUser(userId) {
|
|
187
|
-
return this._authClient.getUser(userId);
|
|
188
|
-
}
|
|
189
|
-
async getOpenIDProviderEndpoints() {
|
|
190
|
-
return this._authClient.getOpenIDProviderEndpoints();
|
|
191
|
-
}
|
|
192
|
-
async getDecodedIdToken(userId) {
|
|
193
|
-
return this._authClient.getDecodedIdToken(userId);
|
|
194
|
-
}
|
|
195
|
-
async getAccessToken(userId) {
|
|
196
|
-
return this._authClient.getAccessToken(userId);
|
|
197
|
-
}
|
|
198
|
-
async exchangeToken(config, userId) {
|
|
199
|
-
return this._authClient.exchangeToken(config, userId);
|
|
200
|
-
}
|
|
201
|
-
async reInitialize(config) {
|
|
202
|
-
return this._authClient.reInitialize(config);
|
|
203
|
-
}
|
|
204
|
-
async revokeAccessToken(userId) {
|
|
205
|
-
return this._authClient.revokeAccessToken(userId);
|
|
206
|
-
}
|
|
207
|
-
static didSignOutFail(afterSignOutUrl) {
|
|
208
|
-
return LegacyThunderIDNodeClient.didSignOutFail(afterSignOutUrl);
|
|
209
|
-
}
|
|
210
|
-
static isSignOutSuccessful(afterSignOutUrl) {
|
|
211
|
-
return LegacyThunderIDNodeClient.isSignOutSuccessful(afterSignOutUrl);
|
|
212
|
-
}
|
|
213
|
-
static protectRoute(callback) {
|
|
214
|
-
if (!this._instance) throw new ThunderIDAuthException("EXPRESS-CLIENT-PR-NF01", "ThunderIDExpressClient is not instantiated", "Create an instance of ThunderIDExpressClient before using calling this method.");
|
|
215
|
-
return protectRoute(this._instance, callback);
|
|
216
|
-
}
|
|
217
|
-
static thunderIDExpressAuth(onSignIn, onSignOut, onError) {
|
|
218
|
-
if (!this._instance) throw new ThunderIDAuthException("EXPRESS-CLIENT-AEA-NF01", "ThunderIDExpressClient is not instantiated", "Create an instance of ThunderIDExpressClient before using calling this method.");
|
|
219
|
-
return thunderIDExpressAuth(this._instance, ThunderIDExpressClient._clientConfig, onSignIn, onSignOut, onError);
|
|
220
|
-
}
|
|
221
|
-
async getStorageManager() {
|
|
222
|
-
return this._authClient.getStorageManager();
|
|
223
|
-
}
|
|
339
|
+
res.json({
|
|
340
|
+
authId: resolvedAuthId,
|
|
341
|
+
challengeToken: flowResponse.challengeToken,
|
|
342
|
+
components: flowResponse.data?.meta?.components ?? [],
|
|
343
|
+
executionId: flowResponse.executionId,
|
|
344
|
+
flowStatus: flowResponse.flowStatus
|
|
345
|
+
});
|
|
346
|
+
} catch (e) {
|
|
347
|
+
logger.error(e.message);
|
|
348
|
+
res.status(500).json({ error: e.message ?? "Flow execution failed" });
|
|
349
|
+
}
|
|
350
|
+
};
|
|
224
351
|
};
|
|
352
|
+
var flow_default = handleFlow;
|
|
225
353
|
|
|
226
354
|
//#endregion
|
|
227
|
-
export { ThunderIDExpressClient };
|
|
355
|
+
export { CookieConfig_default as CookieConfig, SESSION_COOKIE_NAME, ThunderIDExpressClient_default as ThunderIDExpressClient, flow_default as handleFlow, handleSignIn, handleSignOut, protect_default as protect, thunderID };
|
|
@@ -0,0 +1,66 @@
|
|
|
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 express from 'express';
|
|
19
|
+
import { ThunderIDExpressConfig } from '../models/config';
|
|
20
|
+
/**
|
|
21
|
+
* Returns Express middleware that initialises the ThunderID client and attaches
|
|
22
|
+
* it to `req.thunderIDAuth` for use in route handlers and `protect()`.
|
|
23
|
+
*
|
|
24
|
+
* Unlike the old `thunderID()` router, this function does **not** mount any
|
|
25
|
+
* routes automatically. Register sign-in and sign-out handlers explicitly:
|
|
26
|
+
*
|
|
27
|
+
* ```ts
|
|
28
|
+
* app.use(thunderID(config));
|
|
29
|
+
* app.get('/login', handleSignIn());
|
|
30
|
+
* app.get('/logout', handleSignOut());
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @param config - ThunderID Express configuration.
|
|
34
|
+
*/
|
|
35
|
+
declare const thunderID: (config: ThunderIDExpressConfig) => express.RequestHandler;
|
|
36
|
+
/**
|
|
37
|
+
* Returns an Express route handler for the sign-in path.
|
|
38
|
+
*
|
|
39
|
+
* - If the request has no `?code` query param, initiates the OAuth 2.0 redirect.
|
|
40
|
+
* - If the request has `?code`, exchanges the authorization code for tokens,
|
|
41
|
+
* sets the session cookie, and calls `onSignIn`.
|
|
42
|
+
*
|
|
43
|
+
* Must be used after `thunderID()` middleware so that `req.thunderIDAuth` is set.
|
|
44
|
+
*
|
|
45
|
+
* ```ts
|
|
46
|
+
* app.get('/login', handleSignIn());
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
declare const handleSignIn: () => express.RequestHandler;
|
|
50
|
+
/**
|
|
51
|
+
* Returns an Express route handler for the sign-out path.
|
|
52
|
+
*
|
|
53
|
+
* - Clears the session cookie and redirects to the identity provider's
|
|
54
|
+
* end-session endpoint.
|
|
55
|
+
* - When the identity provider redirects back with `?state=sign_out_success`,
|
|
56
|
+
* calls `onSignOut`.
|
|
57
|
+
*
|
|
58
|
+
* Must be used after `thunderID()` middleware so that `req.thunderIDAuth` is set.
|
|
59
|
+
*
|
|
60
|
+
* ```ts
|
|
61
|
+
* app.get('/logout', handleSignOut());
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
declare const handleSignOut: () => express.RequestHandler;
|
|
65
|
+
export { thunderID, handleSignIn, handleSignOut };
|
|
66
|
+
//# sourceMappingURL=authentication.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authentication.d.ts","sourceRoot":"","sources":["../../src/middleware/authentication.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,OAAO,MAAM,SAAS,CAAC;AAG9B,OAAO,EAAC,sBAAsB,EAAC,MAAM,kBAAkB,CAAC;AAExD;;;;;;;;;;;;;;GAcG;AACH,QAAA,MAAM,SAAS,GAAI,QAAQ,sBAAsB,KAAG,OAAO,CAAC,cAsB3D,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,QAAA,MAAM,YAAY,QAAO,OAAO,CAAC,cA6BhC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,QAAA,MAAM,aAAa,QAAO,OAAO,CAAC,cAgDjC,CAAC;AAEF,OAAO,EAAC,SAAS,EAAE,YAAY,EAAE,aAAa,EAAC,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
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 express from 'express';
|
|
19
|
+
/**
|
|
20
|
+
* Returns an Express route handler that drives the embedded sign-in flow loop.
|
|
21
|
+
*
|
|
22
|
+
* Requires `thunderID()` middleware with `mode: 'embedded'` to be mounted first.
|
|
23
|
+
* On each POST, the handler advances the flow one step and returns JSON.
|
|
24
|
+
*
|
|
25
|
+
* **First call** — no `executionId`:
|
|
26
|
+
* ```json
|
|
27
|
+
* { "applicationId": "app-id", "flowType": "SIGN_IN" }
|
|
28
|
+
* ```
|
|
29
|
+
* Response includes `executionId`, `challengeToken`, `authId`, and `components`
|
|
30
|
+
* (the UI elements to render).
|
|
31
|
+
*
|
|
32
|
+
* **Subsequent calls** — continue the flow:
|
|
33
|
+
* ```json
|
|
34
|
+
* { "executionId": "...", "challengeToken": "...", "authId": "...", "inputs": { ... } }
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* **On completion** — flow returns `{ "done": true, "redirectUrl": "/login?code=..." }`.
|
|
38
|
+
* The client navigates to `redirectUrl`, which is handled by `handleSignIn()` to
|
|
39
|
+
* exchange the code and set the session cookie.
|
|
40
|
+
*
|
|
41
|
+
* ```ts
|
|
42
|
+
* app.use(thunderID({ ..., mode: 'embedded' }));
|
|
43
|
+
* app.get('/login', handleSignIn());
|
|
44
|
+
* app.post('/flow/sign-in', handleFlow());
|
|
45
|
+
* app.get('/logout', handleSignOut());
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
declare const handleFlow: () => express.RequestHandler;
|
|
49
|
+
export default handleFlow;
|
|
50
|
+
//# sourceMappingURL=flow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow.d.ts","sourceRoot":"","sources":["../../src/middleware/flow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,OAAO,MAAM,SAAS,CAAC;AAG9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,QAAA,MAAM,UAAU,QAAO,OAAO,CAAC,cAwD9B,CAAC;AAEF,eAAe,UAAU,CAAC"}
|