@webda/auth 0.0.0-stage → 4.0.0-beta.4

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 (59) hide show
  1. package/LICENSE +166 -0
  2. package/README.md +26 -2
  3. package/lib/authentication.service.d.ts +286 -0
  4. package/lib/authentication.service.d.ts.map +1 -0
  5. package/lib/authentication.service.js +798 -0
  6. package/lib/authentication.service.js.map +1 -0
  7. package/lib/compat/upgrade.d.ts +71 -0
  8. package/lib/compat/upgrade.d.ts.map +1 -0
  9. package/lib/compat/upgrade.js +185 -0
  10. package/lib/compat/upgrade.js.map +1 -0
  11. package/lib/email/emailpassword.service.d.ts +241 -0
  12. package/lib/email/emailpassword.service.d.ts.map +1 -0
  13. package/lib/email/emailpassword.service.js +718 -0
  14. package/lib/email/emailpassword.service.js.map +1 -0
  15. package/lib/email/tokens.d.ts +36 -0
  16. package/lib/email/tokens.d.ts.map +1 -0
  17. package/lib/email/tokens.js +46 -0
  18. package/lib/email/tokens.js.map +1 -0
  19. package/lib/errors.d.ts +53 -0
  20. package/lib/errors.d.ts.map +1 -0
  21. package/lib/errors.js +73 -0
  22. package/lib/errors.js.map +1 -0
  23. package/lib/index.d.ts +9 -0
  24. package/lib/index.d.ts.map +1 -0
  25. package/lib/index.js +9 -0
  26. package/lib/index.js.map +1 -0
  27. package/lib/oauth/oauth.service.d.ts +293 -0
  28. package/lib/oauth/oauth.service.d.ts.map +1 -0
  29. package/lib/oauth/oauth.service.js +557 -0
  30. package/lib/oauth/oauth.service.js.map +1 -0
  31. package/lib/provider.d.ts +53 -0
  32. package/lib/provider.d.ts.map +1 -0
  33. package/lib/provider.js +55 -0
  34. package/lib/provider.js.map +1 -0
  35. package/lib/test/authtest.d.ts +39 -0
  36. package/lib/test/authtest.d.ts.map +1 -0
  37. package/lib/test/authtest.js +62 -0
  38. package/lib/test/authtest.js.map +1 -0
  39. package/lib/test/emailtest.d.ts +25 -0
  40. package/lib/test/emailtest.d.ts.map +1 -0
  41. package/lib/test/emailtest.js +39 -0
  42. package/lib/test/emailtest.js.map +1 -0
  43. package/lib/test/fakeoauth.service.d.ts +45 -0
  44. package/lib/test/fakeoauth.service.d.ts.map +1 -0
  45. package/lib/test/fakeoauth.service.js +78 -0
  46. package/lib/test/fakeoauth.service.js.map +1 -0
  47. package/lib/test/stubprovider.js +37 -0
  48. package/lib/test/stubprovider.js.map +1 -0
  49. package/lib/test/v3.d.ts +29 -0
  50. package/lib/test/v3.d.ts.map +1 -0
  51. package/lib/test/v3.js +47 -0
  52. package/lib/test/v3.js.map +1 -0
  53. package/lib/throttle.d.ts +40 -0
  54. package/lib/throttle.d.ts.map +1 -0
  55. package/lib/throttle.js +47 -0
  56. package/lib/throttle.js.map +1 -0
  57. package/package.json +65 -3
  58. package/test/config.json +20 -0
  59. package/webda.module.json +636 -0
@@ -0,0 +1,557 @@
1
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
2
+ var useValue = arguments.length > 2;
3
+ for (var i = 0; i < initializers.length; i++) {
4
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
5
+ }
6
+ return useValue ? value : void 0;
7
+ };
8
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
9
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
10
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
11
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
12
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
13
+ var _, done = false;
14
+ for (var i = decorators.length - 1; i >= 0; i--) {
15
+ var context = {};
16
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
17
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
18
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
19
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
20
+ if (kind === "accessor") {
21
+ if (result === void 0) continue;
22
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
23
+ if (_ = accept(result.get)) descriptor.get = _;
24
+ if (_ = accept(result.set)) descriptor.set = _;
25
+ if (_ = accept(result.init)) initializers.unshift(_);
26
+ }
27
+ else if (_ = accept(result)) {
28
+ if (kind === "field") initializers.unshift(_);
29
+ else descriptor[key] = _;
30
+ }
31
+ }
32
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
+ done = true;
34
+ };
35
+ import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
36
+ import { CookieOptions, registerOperation, Route, runAsSystem, runWithContext, SecureCookie, Service, ServiceParameters, useContext, useCrypto, useDynamicService, WebdaError } from "@webda/core";
37
+ import { useAuthentication } from "../provider.js";
38
+ import { IdentLinkedElsewhere, TokenInvalid, UnsupportedMediaType } from "../errors.js";
39
+ /** OAuthProvider parameters */
40
+ export class OAuthProviderParameters extends ServiceParameters {
41
+ /**
42
+ * @param params - raw parameters
43
+ * @returns this
44
+ */
45
+ load(params = {}) {
46
+ super.load(params);
47
+ this.authorized_uris ?? (this.authorized_uris = []);
48
+ this.redirects = { success: "/", ...(this.redirects ?? {}) };
49
+ return this;
50
+ }
51
+ }
52
+ /** Validity of a pending login, in seconds */
53
+ const PENDING_TTL = 600;
54
+ /**
55
+ * Maximum length of a login `redirect`: the pending login cookie must stay a single cookie (SecureCookie splits
56
+ * values above ~4 KB, and the encrypted cookie is about 1.8 times the size of its content)
57
+ */
58
+ const REDIRECT_MAX = 1024;
59
+ /**
60
+ * @param err - any error
61
+ * @returns the code of a WebdaError.HttpError, undefined for anything else
62
+ */
63
+ function httpErrorCode(err) {
64
+ return typeof err?.getResponseCode === "function" &&
65
+ typeof err?.code === "string" &&
66
+ /^[A-Z][A-Z0-9_]*$/.test(err.code)
67
+ ? err.code
68
+ : undefined;
69
+ }
70
+ /**
71
+ * Loggable reason of an error: library messages may contain tokens or their payload, so only a short code or the
72
+ * error class name is kept
73
+ * @param err - any error
74
+ * @returns a reason without any part of the message
75
+ */
76
+ export function safeErrorReason(err) {
77
+ const safe = (value) => typeof value === "string" && /^[A-Za-z0-9_.-]{1,40}$/.test(value);
78
+ const name = safe(err?.name) ? err.name : "Error";
79
+ const code = err?.code;
80
+ if (safe(code) || (typeof code === "number" && Number.isFinite(code))) {
81
+ return `${name}(${code})`;
82
+ }
83
+ return name;
84
+ }
85
+ /** Credentials keys kept from a client `tokens` body */
86
+ const TOKEN_KEYS = ["id_token", "access_token", "refresh_token", "expiry_date", "token_type", "scope"];
87
+ /** Maximum length of a kept credentials value */
88
+ const TOKEN_VALUE_MAX = 4096;
89
+ /**
90
+ * Keep only the known credentials keys, as bounded strings or finite numbers
91
+ * @param tokens - client provided credentials
92
+ * @returns the sanitised credentials
93
+ */
94
+ export function sanitizeTokens(tokens) {
95
+ const out = {};
96
+ for (const key of TOKEN_KEYS) {
97
+ const value = tokens?.[key];
98
+ if ((typeof value === "string" && value.length <= TOKEN_VALUE_MAX) ||
99
+ (typeof value === "number" && Number.isFinite(value))) {
100
+ out[key] = value;
101
+ }
102
+ }
103
+ return out;
104
+ }
105
+ /**
106
+ * @param url - absolute or relative url
107
+ * @param params - query parameters to add
108
+ * @returns the url with the parameters appended
109
+ */
110
+ function withQuery(url, params) {
111
+ const query = new URLSearchParams(params).toString();
112
+ const hash = url.indexOf("#");
113
+ const [base, fragment] = hash < 0 ? [url, ""] : [url.substring(0, hash), url.substring(hash)];
114
+ return `${base}${base.includes("?") ? "&" : "?"}${query}${fragment}`;
115
+ }
116
+ /**
117
+ * @param url - candidate
118
+ * @returns the parsed url when it is an absolute http(s) url without credentials
119
+ */
120
+ function parseHttpUrl(url) {
121
+ if (typeof url !== "string")
122
+ return undefined;
123
+ try {
124
+ const parsed = new URL(url);
125
+ if (!["http:", "https:"].includes(parsed.protocol) || parsed.username || parsed.password)
126
+ return undefined;
127
+ return parsed;
128
+ }
129
+ catch {
130
+ return undefined;
131
+ }
132
+ }
133
+ /**
134
+ * Constant-time comparison of two secrets
135
+ * @param a - received value
136
+ * @param b - expected value
137
+ * @returns true when equal
138
+ */
139
+ function sameSecret(a, b) {
140
+ const left = Buffer.from(a);
141
+ const right = Buffer.from(b);
142
+ return left.length === right.length && timingSafeEqual(left, right);
143
+ }
144
+ /**
145
+ * @param bytes - entropy
146
+ * @returns a random base64url string
147
+ */
148
+ function randomSecret(bytes) {
149
+ return randomBytes(bytes).toString("base64url");
150
+ }
151
+ /**
152
+ * Base of the OAuth 2.0 / OpenID Connect login providers
153
+ *
154
+ * Exposes, under `url` (default `/auth/<providerName>`):
155
+ * - `GET <url>{?redirect}`: starts a login with a random `state`, a PKCE (S256) verifier and an OpenID `nonce`, kept
156
+ * in a dedicated encrypted cookie (10 min, HttpOnly, SameSite=Lax, path `url`), then redirects to the provider;
157
+ * `redirect` must match `authorized_uris`
158
+ * - `GET <url>/callback`: consumes that cookie, checks the state, exchanges the code (`handleCallback`) and hands
159
+ * the identity to `Authentication.complete()`; never throws, failures go to `redirects.failure?reason=<CODE>`
160
+ * - operation `Auth.<Provider>.Token` (`POST auth/<providerName>/token`, JSON body `{ token }` or `{ tokens }`) for
161
+ * non-browser clients; it never links an identity to the session user
162
+ *
163
+ * Subclasses implement `providerName`, `getAuthorizationUrl`, `handleCallback` and `handleToken`; the provider of the
164
+ * returned identities is always forced to `providerName`.
165
+ */
166
+ let OAuthProvider = (() => {
167
+ var _a;
168
+ let _classSuper = Service;
169
+ let _instanceExtraInitializers = [];
170
+ let _login_decorators;
171
+ let _callback_decorators;
172
+ return _a = class OAuthProvider extends _classSuper {
173
+ /**
174
+ * Called after a successful `Authentication.complete()` (status ok or mfa_required)
175
+ * @param _identity - the identity
176
+ * @param _result - the result
177
+ * @param _source - browser callback or token operation
178
+ * @param _request - the token operation request (token operation only)
179
+ */
180
+ async onAuthenticated(_identity, _result, _source, _request) {
181
+ // Hook for providers
182
+ }
183
+ /**
184
+ * @returns false when the provider works without client secret (public clients)
185
+ */
186
+ requiresClientSecret() {
187
+ return true;
188
+ }
189
+ /**
190
+ * @returns the name of the pending login cookie
191
+ */
192
+ getCookieName() {
193
+ return `webda_oauth_${this.providerName}`;
194
+ }
195
+ /** @override */
196
+ resolve() {
197
+ var _b;
198
+ super.resolve();
199
+ (_b = this.parameters).url ?? (_b.url = `/auth/${this.providerName}`);
200
+ return this;
201
+ }
202
+ /** @override */
203
+ async init() {
204
+ await super.init();
205
+ const name = `${this.constructor.name} '${this.getName()}'`;
206
+ const params = this.parameters;
207
+ if (!params.client_id) {
208
+ throw new Error(`${name} requires the 'client_id' parameter`);
209
+ }
210
+ if (this.requiresClientSecret() && !params.client_secret) {
211
+ throw new Error(`${name} requires the 'client_secret' parameter`);
212
+ }
213
+ if (!params.redirects?.failure) {
214
+ throw new Error(`${name} requires the 'redirects.failure' parameter`);
215
+ }
216
+ if (!useDynamicService("Authentication")) {
217
+ throw new Error(`${name} requires the Authentication service`);
218
+ }
219
+ for (const uri of params.authorized_uris ?? []) {
220
+ if (!parseHttpUrl(uri)) {
221
+ throw new Error(`${name}: authorized_uris entries must be absolute http(s) urls, got '${uri}'`);
222
+ }
223
+ }
224
+ return this;
225
+ }
226
+ /**
227
+ * Register `Auth.<Provider>.Token`: its id and path depend on the provider name
228
+ * @override
229
+ */
230
+ initOperations() {
231
+ super.initOperations();
232
+ const name = this.providerName;
233
+ const id = this.getOperationId(`Auth.${name.substring(0, 1).toUpperCase()}${name.substring(1)}.Token`);
234
+ if (!id)
235
+ return;
236
+ registerOperation(id, {
237
+ service: this.getName(),
238
+ method: "token",
239
+ // Schemas are compiled per class: a shared named schema serves every provider
240
+ input: "Webda/OAuthTokenRequest",
241
+ summary: `Log in with a ${name} token`,
242
+ tags: ["Authentication"],
243
+ rest: { method: "post", path: `auth/${name}/token` }
244
+ });
245
+ }
246
+ /**
247
+ * @returns public info
248
+ */
249
+ getPublicInfo() {
250
+ return { name: this.providerName, type: "oauth", startUrl: this.parameters.url ?? `/auth/${this.providerName}` };
251
+ }
252
+ /**
253
+ * Log in with a token obtained by the client from the provider
254
+ *
255
+ * Requires a JSON request (a cross-site form or `text/plain` POST is refused). A request carrying a logged-in
256
+ * session never links the identity to that user: an identity owned by another user is refused
257
+ * (IDENT_LINKED_ELSEWHERE), a new or unowned one gets a fresh session.
258
+ * @param token - token (an ID token for OpenID Connect providers)
259
+ * @param tokens - credentials obtained from the provider (v3 body)
260
+ * @returns the auth result
261
+ */
262
+ async token(token, tokens) {
263
+ const ctx = useContext();
264
+ this.requireJson(ctx);
265
+ if (token !== undefined && (typeof token !== "string" || !token)) {
266
+ throw new WebdaError.BadRequest("token must be a non-empty string");
267
+ }
268
+ if (tokens !== undefined && (tokens === null || typeof tokens !== "object" || Array.isArray(tokens))) {
269
+ throw new WebdaError.BadRequest("tokens must be an object");
270
+ }
271
+ if (!token && !tokens) {
272
+ throw new WebdaError.BadRequest("token or tokens is required");
273
+ }
274
+ // Only known credentials keys are verified, stored or published
275
+ tokens = tokens ? sanitizeTokens(tokens) : undefined;
276
+ let identity;
277
+ try {
278
+ identity = this.ownIdentity(this.checkIdentity(await this.handleToken({ token, tokens })));
279
+ }
280
+ catch (err) {
281
+ if (httpErrorCode(err))
282
+ throw err;
283
+ // Fail closed: an unexpected verification failure is an invalid token
284
+ this.log("WARN", `${this.providerName} token verification failed:`, safeErrorReason(err));
285
+ throw new TokenInvalid();
286
+ }
287
+ await this.leaveForeignSession(ctx, identity);
288
+ const result = await useAuthentication().complete(identity);
289
+ await this.onAuthenticated(identity, result, "token", { token, tokens });
290
+ return result;
291
+ }
292
+ /**
293
+ * Refuse a request that is not JSON: cross-site requests can only send form or `text/plain` bodies without a
294
+ * preflight
295
+ * @param ctx - operation context
296
+ * @throws UnsupportedMediaType when the HTTP request is not `application/json`
297
+ */
298
+ requireJson(ctx) {
299
+ const http = ctx?.getHttpContext?.();
300
+ if (!http)
301
+ return;
302
+ const type = `${http.getUniqueHeader?.("content-type", "") ?? ""}`;
303
+ if (!/^application\/json\s*(;|$)/i.test(type.trim())) {
304
+ throw new UnsupportedMediaType();
305
+ }
306
+ }
307
+ /**
308
+ * The token operation never links: with a logged-in session, an identity owned by another user is refused and a
309
+ * new or unowned one starts a fresh session
310
+ * @param ctx - operation context
311
+ * @param identity - verified identity
312
+ * @throws IdentLinkedElsewhere when the identity belongs to another user than the session one
313
+ */
314
+ async leaveForeignSession(ctx, identity) {
315
+ if (!ctx?.getSession?.()?.isLogged())
316
+ return;
317
+ const current = ctx.getCurrentUserId();
318
+ const ident = await runAsSystem(() => useAuthentication().findIdent(identity.provider, identity.providerUid));
319
+ const owner = ident?.getUser()?.toString();
320
+ if (owner === current)
321
+ return;
322
+ if (owner) {
323
+ throw new IdentLinkedElsewhere();
324
+ }
325
+ ctx.newSession();
326
+ }
327
+ /**
328
+ * @param identity - identity returned by the subclass
329
+ * @returns the identity
330
+ * @throws TokenInvalid when it has no subject
331
+ */
332
+ checkIdentity(identity) {
333
+ if (!identity?.providerUid || typeof identity.providerUid !== "string") {
334
+ throw new TokenInvalid("Provider returned no subject");
335
+ }
336
+ return identity;
337
+ }
338
+ /**
339
+ * @param identity - identity returned by the subclass
340
+ * @returns the identity, always attributed to this provider
341
+ */
342
+ ownIdentity(identity) {
343
+ return {
344
+ ...identity,
345
+ provider: this.providerName,
346
+ amr: identity.amr?.length ? identity.amr : ["oauth"]
347
+ };
348
+ }
349
+ /**
350
+ * Check a post-login target against `authorized_uris`: same origin, and the listed path or below it; an encoded
351
+ * slash or backslash in the path is refused
352
+ * @param redirect - candidate
353
+ * @returns the normalised url, undefined when not allowed
354
+ */
355
+ allowedRedirect(redirect) {
356
+ if (typeof redirect !== "string" || redirect.length > REDIRECT_MAX || /%2f|%5c/i.test(redirect.split(/[?#]/)[0])) {
357
+ return undefined;
358
+ }
359
+ const target = parseHttpUrl(redirect);
360
+ if (!target)
361
+ return undefined;
362
+ for (const uri of this.parameters.authorized_uris ?? []) {
363
+ const allowed = parseHttpUrl(uri);
364
+ if (!allowed || allowed.origin !== target.origin)
365
+ continue;
366
+ const path = allowed.pathname;
367
+ if (target.pathname === path || target.pathname.startsWith(path.endsWith("/") ? path : `${path}/`)) {
368
+ return target.href;
369
+ }
370
+ }
371
+ return undefined;
372
+ }
373
+ /**
374
+ * @param ctx - web context
375
+ * @returns the callback url sent to the provider
376
+ */
377
+ getRedirectUri(ctx) {
378
+ return this.parameters.redirect_uri ?? ctx.getHttpContext().getAbsoluteUrl(`${this.parameters.url ?? ""}/callback`);
379
+ }
380
+ /**
381
+ * Set (or clear, without value) the pending login cookie, scoped to the callback path: the path of the effective
382
+ * redirect_uri, which includes any deployment prefix (API Gateway stage, path-stripping proxy) the routes do not see
383
+ * @param ctx - web context
384
+ * @param redirectUri - callback url
385
+ * @param value - encrypted pending login
386
+ */
387
+ sendPendingCookie(ctx, redirectUri, value) {
388
+ const callback = parseHttpUrl(redirectUri);
389
+ const options = new CookieOptions({
390
+ name: this.getCookieName(),
391
+ path: callback?.pathname || "/",
392
+ maxAge: value ? PENDING_TTL : 0,
393
+ sameSite: "lax",
394
+ httpOnly: true
395
+ }, ctx.getHttpContext());
396
+ // Secure when the request or the callback is https
397
+ options.secure = options.secure || callback?.protocol === "https:";
398
+ if (value) {
399
+ SecureCookie.sendCookie(ctx, this.getCookieName(), value, options);
400
+ }
401
+ else {
402
+ ctx.cookie(this.getCookieName(), "", options);
403
+ }
404
+ }
405
+ /**
406
+ * Read and clear the pending login cookie
407
+ * @param ctx - web context
408
+ * @returns the pending login, undefined when absent, invalid, expired or of another provider
409
+ */
410
+ async consumePending(ctx) {
411
+ const raw = ctx.getHttpContext()?.getCookies?.()?.[this.getCookieName()];
412
+ // Always cleared, on the path it was set on (the callback): single use
413
+ this.sendPendingCookie(ctx, this.getRedirectUri(ctx));
414
+ if (typeof raw !== "string" || !raw)
415
+ return undefined;
416
+ let pending;
417
+ try {
418
+ pending = await useCrypto().decrypt(raw);
419
+ }
420
+ catch {
421
+ return undefined;
422
+ }
423
+ if (!pending ||
424
+ pending.provider !== this.providerName ||
425
+ typeof pending.state !== "string" ||
426
+ typeof pending.verifier !== "string" ||
427
+ typeof pending.nonce !== "string" ||
428
+ !(Date.now() <= pending.expires)) {
429
+ return undefined;
430
+ }
431
+ return pending;
432
+ }
433
+ /**
434
+ * Redirect without caching
435
+ * @param ctx - web context
436
+ * @param url - target
437
+ */
438
+ redirect(ctx, url) {
439
+ ctx.setHeader("Cache-Control", "no-store");
440
+ ctx.redirect(url);
441
+ }
442
+ /**
443
+ * @param ctx - web context
444
+ * @param reason - failure code
445
+ */
446
+ fail(ctx, reason) {
447
+ this.redirect(ctx, withQuery(this.parameters.redirects.failure, { reason }));
448
+ }
449
+ /**
450
+ * Start a login: redirect the browser to the provider
451
+ * @param ctx - web context
452
+ */
453
+ async login(ctx) {
454
+ try {
455
+ const requested = ctx.parameter("redirect");
456
+ let redirect;
457
+ if (requested !== undefined && requested !== "") {
458
+ redirect = this.allowedRedirect(requested);
459
+ if (!redirect) {
460
+ this.fail(ctx, "REDIRECT_NOT_ALLOWED");
461
+ return;
462
+ }
463
+ }
464
+ const pending = {
465
+ provider: this.providerName,
466
+ state: randomSecret(32),
467
+ verifier: randomSecret(32),
468
+ nonce: randomSecret(24),
469
+ redirect,
470
+ redirectUri: this.getRedirectUri(ctx),
471
+ expires: Date.now() + PENDING_TTL * 1000
472
+ };
473
+ const url = await this.getAuthorizationUrl({
474
+ state: pending.state,
475
+ redirectUri: pending.redirectUri,
476
+ scope: this.parameters.scope ?? [],
477
+ codeChallenge: createHash("sha256").update(pending.verifier).digest("base64url"),
478
+ codeChallengeMethod: "S256",
479
+ nonce: pending.nonce
480
+ });
481
+ this.sendPendingCookie(ctx, pending.redirectUri, await useCrypto().encrypt(pending));
482
+ this.redirect(ctx, url);
483
+ }
484
+ catch (err) {
485
+ this.log("ERROR", `Cannot start ${this.providerName} login:`, safeErrorReason(err));
486
+ this.fail(ctx, "OAUTH_ERROR");
487
+ }
488
+ }
489
+ /**
490
+ * Provider callback: verify the state, exchange the code, complete the login and redirect; never throws
491
+ * @param ctx - web context
492
+ */
493
+ async callback(ctx) {
494
+ try {
495
+ const pending = await this.consumePending(ctx);
496
+ const state = ctx.parameter("state");
497
+ if (!pending || typeof state !== "string" || !sameSecret(state, pending.state)) {
498
+ this.fail(ctx, "STATE_MISMATCH");
499
+ return;
500
+ }
501
+ const code = ctx.parameter("code");
502
+ if (ctx.parameter("error") !== undefined || typeof code !== "string" || !code) {
503
+ this.fail(ctx, "PROVIDER_ERROR");
504
+ return;
505
+ }
506
+ const result = await runWithContext(ctx, async () => {
507
+ const identity = this.ownIdentity(this.checkIdentity(await this.handleCallback({
508
+ code,
509
+ redirectUri: pending.redirectUri,
510
+ codeVerifier: pending.verifier,
511
+ nonce: pending.nonce
512
+ })));
513
+ const res = await useAuthentication().complete(identity);
514
+ await this.onAuthenticated(identity, res, "callback");
515
+ return res;
516
+ });
517
+ const target = pending.redirect ?? this.parameters.redirects.success ?? "/";
518
+ this.redirect(ctx, result.status === "mfa_required" ? withQuery(target, { mfa: "required" }) : target);
519
+ }
520
+ catch (err) {
521
+ const code = httpErrorCode(err);
522
+ if (!code) {
523
+ this.log("ERROR", `${this.providerName} callback failed:`, safeErrorReason(err));
524
+ }
525
+ this.fail(ctx, code ?? "OAUTH_ERROR");
526
+ }
527
+ }
528
+ constructor() {
529
+ super(...arguments);
530
+ __runInitializers(this, _instanceExtraInitializers);
531
+ }
532
+ },
533
+ (() => {
534
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
535
+ _login_decorators = [Route(".{?redirect?}", ["GET"], {
536
+ get: {
537
+ summary: "Start an OAuth login",
538
+ description: "Redirects to the provider; `redirect` must match the provider authorized_uris",
539
+ responses: { "302": { description: "Redirect to the provider, or to redirects.failure" } }
540
+ }
541
+ })];
542
+ _callback_decorators = [Route("./callback{?code?,state?,error?}", ["GET"], {
543
+ get: {
544
+ summary: "OAuth callback",
545
+ description: "Completes the login started by the login route",
546
+ responses: { "302": { description: "Redirect to the login target, or to redirects.failure?reason=CODE" } }
547
+ }
548
+ })];
549
+ __esDecorate(_a, null, _login_decorators, { kind: "method", name: "login", static: false, private: false, access: { has: obj => "login" in obj, get: obj => obj.login }, metadata: _metadata }, null, _instanceExtraInitializers);
550
+ __esDecorate(_a, null, _callback_decorators, { kind: "method", name: "callback", static: false, private: false, access: { has: obj => "callback" in obj, get: obj => obj.callback }, metadata: _metadata }, null, _instanceExtraInitializers);
551
+ if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
552
+ })(),
553
+ _a.Parameters = OAuthProviderParameters,
554
+ _a;
555
+ })();
556
+ export { OAuthProvider };
557
+ //# sourceMappingURL=oauth.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.service.js","sourceRoot":"","sources":["../../src/oauth/oauth.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import { type ProviderInfo, type ResolvedIdentity, type Service } from "@webda/core";
2
+ import type { Authentication } from "./authentication.service.js";
3
+ /** A login method plugged into {@link Authentication} */
4
+ export interface AuthProvider extends Service {
5
+ /** Unique provider name, used in ident keys ("email", "google") */
6
+ readonly providerName: string;
7
+ /**
8
+ * @returns what clients see in Auth.Providers
9
+ */
10
+ getPublicInfo(): ProviderInfo;
11
+ /**
12
+ * Email rules of this provider; when absent, Authentication reads the provider service parameters
13
+ * @returns the email policy
14
+ */
15
+ getEmailPolicy?(): ProviderEmailPolicy;
16
+ }
17
+ /** Per-provider rules on asserted emails; read from the provider service parameters */
18
+ export interface ProviderEmailPolicy {
19
+ /**
20
+ * Only identities whose email domain is listed may log in (case-insensitive, exact domain match, no wildcard).
21
+ * The email must also be verified and trusted (see trustEmailVerification). An empty list refuses everyone.
22
+ * Undefined means all domains.
23
+ */
24
+ allowedEmailDomains?: string[];
25
+ /**
26
+ * Whether the provider's emailVerified claim is believed: true (default) = all domains, false = never,
27
+ * string[] = only these domains.
28
+ */
29
+ trustEmailVerification?: boolean | string[];
30
+ }
31
+ /**
32
+ * @param email - an email address
33
+ * @returns the lowercased part after the last "@", undefined if none
34
+ */
35
+ export declare function emailDomain(email: string): string | undefined;
36
+ /**
37
+ * Apply a provider email policy to a resolved identity without mutating it
38
+ * @param identity - identity asserted by the provider
39
+ * @param policy - the provider policy, if any
40
+ * @returns the identity to use (a copy with emailVerified forced to false when the claim is not trusted)
41
+ * @throws EmailDomainNotAllowed when the email is missing or its domain is not allowed
42
+ */
43
+ export declare function applyEmailPolicy(identity: ResolvedIdentity, policy: ProviderEmailPolicy | undefined): ResolvedIdentity;
44
+ /**
45
+ * @param service - any service
46
+ * @returns true when it implements AuthProvider
47
+ */
48
+ export declare function isAuthProvider(service: any): service is AuthProvider;
49
+ /**
50
+ * @returns the Authentication service
51
+ */
52
+ export declare function useAuthentication(): Authentication;
53
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,KAAK,OAAO,EAAqB,MAAM,aAAa,CAAC;AACxG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAGlE,yDAAyD;AACzD,MAAM,WAAW,YAAa,SAAQ,OAAO;IAC3C,mEAAmE;IACnE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;OAEG;IACH,aAAa,IAAI,YAAY,CAAC;IAC9B;;;OAGG;IACH,cAAc,CAAC,IAAI,mBAAmB,CAAC;CACxC;AAED,uFAAuF;AACvF,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B;;;OAGG;IACH,sBAAsB,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,CAAC;CAC7C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQ7D;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,EAAE,mBAAmB,GAAG,SAAS,GACtC,gBAAgB,CAmBlB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,IAAI,YAAY,CAEpE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,CAElD"}