@nestjs/authentication 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/account/password-reset.service.d.ts +8 -2
- package/dist/account/password-reset.service.js +15 -3
- package/dist/errors/magic-link.error.d.ts +4 -3
- package/dist/errors/magic-link.error.js +5 -4
- package/dist/interfaces/magic-link.interface.d.ts +2 -1
- package/dist/interfaces/oidc.interface.d.ts +9 -1
- package/dist/magic-link/magic-link.service.d.ts +4 -1
- package/dist/magic-link/magic-link.service.js +40 -10
- package/dist/oidc/oidc.service.d.ts +1 -0
- package/dist/oidc/oidc.service.js +22 -8
- package/package.json +8 -8
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type OnModuleDestroy } from '@nestjs/common';
|
|
2
|
+
import { AuthenticationScope } from '../context/authentication-scope.service.js';
|
|
2
3
|
import { AuthenticationRegistry } from '../services/authentication-registry.service.js';
|
|
3
4
|
import { AuthenticationStorage } from '../storage/authentication.storage.js';
|
|
4
5
|
import { AuthenticationEvents } from '../events/authentication-events.service.js';
|
|
@@ -35,13 +36,14 @@ export declare class PasswordResetService implements OnModuleDestroy {
|
|
|
35
36
|
private readonly tokens;
|
|
36
37
|
private readonly signInService;
|
|
37
38
|
private readonly events;
|
|
39
|
+
private readonly scope;
|
|
38
40
|
private static readonly logger;
|
|
39
41
|
private readonly options?;
|
|
40
42
|
private readonly ttl;
|
|
41
43
|
private readonly inFlight;
|
|
42
44
|
constructor(storage: AuthenticationStorage, registry: AuthenticationRegistry, hasher: PasswordHasher, sessions: SessionService, tokens: TokenService, signInService: SignInService, options?: {
|
|
43
45
|
passwordReset?: PasswordResetOptions;
|
|
44
|
-
}, events?: AuthenticationEvents);
|
|
46
|
+
}, events?: AuthenticationEvents, scope?: AuthenticationScope);
|
|
45
47
|
/**
|
|
46
48
|
* Starts a reset for `email`, if it belongs to an account: the link goes
|
|
47
49
|
* to `PasswordResetHandler.send()`. Returns at once, before the account is
|
|
@@ -56,7 +58,11 @@ export declare class PasswordResetService implements OnModuleDestroy {
|
|
|
56
58
|
* changed its address or password since the link was sent. `null` too,
|
|
57
59
|
* before the token is looked up (so the link still works), for a password
|
|
58
60
|
* `PasswordHasher` refuses: not a string, empty, or over 4 KiB. Check your
|
|
59
|
-
* own password rules before calling it.
|
|
61
|
+
* own password rules before calling it. With `signIn`, a request from
|
|
62
|
+
* another origin than the app's own and `session.trustedOrigins` gets a
|
|
63
|
+
* `ForbiddenException` first, as `SignInService.signIn()` does, so the link
|
|
64
|
+
* and the password stay as they were. Without `signIn`, the origin is not
|
|
65
|
+
* checked.
|
|
60
66
|
*/
|
|
61
67
|
reset(token: string, password: string, { signIn }?: ResetPasswordOptions): Promise<PasswordResetResult | null>;
|
|
62
68
|
onModuleDestroy(): Promise<void>;
|
|
@@ -12,6 +12,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
12
12
|
};
|
|
13
13
|
var PasswordResetService_1;
|
|
14
14
|
import { Inject, Injectable, Logger, Optional } from '@nestjs/common';
|
|
15
|
+
import { AuthenticationScope } from '../context/authentication-scope.service.js';
|
|
15
16
|
import { AuthenticationRegistry } from '../services/authentication-registry.service.js';
|
|
16
17
|
import { AuthenticationStorage } from '../storage/authentication.storage.js';
|
|
17
18
|
import { AUTHENTICATION_MODULE_OPTIONS } from '../authentication.constants.js';
|
|
@@ -45,7 +46,7 @@ import { isMailableEmail, normalizeEmail } from './email.util.js';
|
|
|
45
46
|
* the token: mail scanners and link previews follow GET links.
|
|
46
47
|
*/
|
|
47
48
|
let PasswordResetService = PasswordResetService_1 = class PasswordResetService {
|
|
48
|
-
constructor(storage, registry, hasher, sessions, tokens, signInService, options, events = new AuthenticationEvents()) {
|
|
49
|
+
constructor(storage, registry, hasher, sessions, tokens, signInService, options, events = new AuthenticationEvents(), scope = new AuthenticationScope()) {
|
|
49
50
|
this.storage = storage;
|
|
50
51
|
this.registry = registry;
|
|
51
52
|
this.hasher = hasher;
|
|
@@ -53,6 +54,7 @@ let PasswordResetService = PasswordResetService_1 = class PasswordResetService {
|
|
|
53
54
|
this.tokens = tokens;
|
|
54
55
|
this.signInService = signInService;
|
|
55
56
|
this.events = events;
|
|
57
|
+
this.scope = scope;
|
|
56
58
|
this.inFlight = new Set();
|
|
57
59
|
this.options = options?.passwordReset;
|
|
58
60
|
if (this.options) {
|
|
@@ -87,10 +89,19 @@ let PasswordResetService = PasswordResetService_1 = class PasswordResetService {
|
|
|
87
89
|
* changed its address or password since the link was sent. `null` too,
|
|
88
90
|
* before the token is looked up (so the link still works), for a password
|
|
89
91
|
* `PasswordHasher` refuses: not a string, empty, or over 4 KiB. Check your
|
|
90
|
-
* own password rules before calling it.
|
|
92
|
+
* own password rules before calling it. With `signIn`, a request from
|
|
93
|
+
* another origin than the app's own and `session.trustedOrigins` gets a
|
|
94
|
+
* `ForbiddenException` first, as `SignInService.signIn()` does, so the link
|
|
95
|
+
* and the password stay as they were. Without `signIn`, the origin is not
|
|
96
|
+
* checked.
|
|
91
97
|
*/
|
|
92
98
|
async reset(token, password, { signIn = false } = {}) {
|
|
93
99
|
const { handler } = this.feature();
|
|
100
|
+
// Signing in would refuse this request at the end, after the link is spent and the password
|
|
101
|
+
// changed: refuse it before, whatever the token is.
|
|
102
|
+
if (signIn) {
|
|
103
|
+
this.signInService.refuseCrossOrigin(this.scope.exchange()?.request);
|
|
104
|
+
}
|
|
94
105
|
if (typeof token !== 'string' || !TOKEN_PATTERN.test(token) || !isHashablePassword(password)) {
|
|
95
106
|
return null;
|
|
96
107
|
}
|
|
@@ -178,7 +189,8 @@ PasswordResetService = PasswordResetService_1 = __decorate([
|
|
|
178
189
|
PasswordHasher,
|
|
179
190
|
SessionService,
|
|
180
191
|
TokenService,
|
|
181
|
-
SignInService, Object, AuthenticationEvents
|
|
192
|
+
SignInService, Object, AuthenticationEvents,
|
|
193
|
+
AuthenticationScope])
|
|
182
194
|
], PasswordResetService);
|
|
183
195
|
export { PasswordResetService };
|
|
184
196
|
/**
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { AuthenticationError } from './authentication.error.js';
|
|
2
2
|
/**
|
|
3
3
|
* A link was presented in a browser other than the one that requested it
|
|
4
|
-
* (see `magicLink.bindToBrowser`)
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* (see `magicLink.bindToBrowser`), or in that browser after it requested
|
|
5
|
+
* five newer ones. The one refusal `consume()` tells apart: the customer
|
|
6
|
+
* can act on it (open the latest link where they asked for it, or request
|
|
7
|
+
* a new one here), and it is decided before the link is
|
|
7
8
|
* looked up, so it reveals nothing about the token. Unknown, used, expired
|
|
8
9
|
* and refused links share one answer, `null`.
|
|
9
10
|
*
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { AuthenticationError } from './authentication.error.js';
|
|
2
2
|
/**
|
|
3
3
|
* A link was presented in a browser other than the one that requested it
|
|
4
|
-
* (see `magicLink.bindToBrowser`)
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* (see `magicLink.bindToBrowser`), or in that browser after it requested
|
|
5
|
+
* five newer ones. The one refusal `consume()` tells apart: the customer
|
|
6
|
+
* can act on it (open the latest link where they asked for it, or request
|
|
7
|
+
* a new one here), and it is decided before the link is
|
|
7
8
|
* looked up, so it reveals nothing about the token. Unknown, used, expired
|
|
8
9
|
* and refused links share one answer, `null`.
|
|
9
10
|
*
|
|
@@ -13,7 +14,7 @@ import { AuthenticationError } from './authentication.error.js';
|
|
|
13
14
|
*/
|
|
14
15
|
export class MagicLinkError extends AuthenticationError {
|
|
15
16
|
constructor() {
|
|
16
|
-
super('Open the link in the browser you requested it from, or request a new one here', { code: 'not_this_browser' });
|
|
17
|
+
super('Open the latest link in the browser you requested it from, or request a new one here', { code: 'not_this_browser' });
|
|
17
18
|
/** Why the link was refused: the only reason apps are told. */
|
|
18
19
|
this.reason = 'not-this-browser';
|
|
19
20
|
this.name = 'MagicLinkError';
|
|
@@ -23,7 +23,8 @@ export interface MagicLinkOptions {
|
|
|
23
23
|
* Whether a link works only in the browser that requested it. Default
|
|
24
24
|
* `true`: `create()` sets a transaction cookie, and `consume()` refuses a
|
|
25
25
|
* link the browser holds no cookie for (`magic-link-refused`,
|
|
26
|
-
* `not-this-browser`).
|
|
26
|
+
* `not-this-browser`). The cookie keeps the last five links the browser
|
|
27
|
+
* requested: a "resend" does not void the link before it. Without it, anyone can request a link for their
|
|
27
28
|
* own address and get someone else to open it, which signs that person's
|
|
28
29
|
* browser in to the attacker's account (login CSRF). `false` trades that
|
|
29
30
|
* for links that work on another device than the one that asked for them
|
|
@@ -45,8 +45,16 @@ export interface OidcOptions extends OidcClientOptions {
|
|
|
45
45
|
* The public URL of your callback route, the redirect URI you register
|
|
46
46
|
* with each provider. `:provider` is replaced by the provider's name:
|
|
47
47
|
* `https://app.example.com/auth/oidc/:provider/callback`.
|
|
48
|
+
*
|
|
49
|
+
* An app served under several domains passes a function of the request
|
|
50
|
+
* instead, called on the login and again on the callback: both must
|
|
51
|
+
* answer the same URL, or the provider refuses the code. Check the host
|
|
52
|
+
* against your own list of domains rather than echoing the header, and
|
|
53
|
+
* register every URL it can answer with each provider. The transaction
|
|
54
|
+
* cookie is bound to the host that set it, so a login finishes on the
|
|
55
|
+
* domain where it started.
|
|
48
56
|
*/
|
|
49
|
-
callbackUrl: string;
|
|
57
|
+
callbackUrl: string | ((request: OidcRequest) => string | Promise<string>);
|
|
50
58
|
providers: Record<string, OidcProviderConfig>;
|
|
51
59
|
/** Where to land after sign-in when the login had no `redirectTo`. Default `/`. */
|
|
52
60
|
redirectAfterLogin?: string;
|
|
@@ -18,7 +18,9 @@ import type { MagicLinkOptions, MagicLinkRequest, CreatedMagicLink } from '../in
|
|
|
18
18
|
* site's page must not start a link here), and sets an `HttpOnly`,
|
|
19
19
|
* `SameSite=Lax` cookie, `__Host-magic_link_tx`, holding a secret that no
|
|
20
20
|
* link carries; the store keys the link by the token and that secret
|
|
21
|
-
* together, so `consume()` finds it only with the cookie. The
|
|
21
|
+
* together, so `consume()` finds it only with the cookie. The cookie holds
|
|
22
|
+
* the secrets of the last five links the browser requested, so a "resend"
|
|
23
|
+
* leaves the link before it usable there. The `__Host-`
|
|
22
24
|
* prefix keeps sibling subdomains from planting one. So the link's page
|
|
23
25
|
* must be on the same site as the API, as the session cookie requires
|
|
24
26
|
* anyway, and a link forwarded to another browser or device, or read from
|
|
@@ -73,6 +75,7 @@ export declare class MagicLinkService {
|
|
|
73
75
|
private feature;
|
|
74
76
|
/** The generic answer: which refusal it was is told only by the event. */
|
|
75
77
|
private refuse;
|
|
78
|
+
private pendingCookie;
|
|
76
79
|
private txCookie;
|
|
77
80
|
private setCookie;
|
|
78
81
|
private now;
|
|
@@ -37,6 +37,24 @@ function linkId(token, binding) {
|
|
|
37
37
|
function hintOf(token) {
|
|
38
38
|
return sha256(`nestjs-authentication magic-link hint ${token}`).slice(0, 12);
|
|
39
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* How many links a browser holds the secrets of: a "resend" leaves the
|
|
42
|
+
* links it requested before usable there, up to this many.
|
|
43
|
+
*/
|
|
44
|
+
const PENDING_LINKS = 5;
|
|
45
|
+
const HINT_PATTERN = /^[\w-]{12}$/;
|
|
46
|
+
/** The links in the cookie, newest first: `<hint>.<secret>`, joined by `~`. Anything else is dropped. */
|
|
47
|
+
function readPending(value) {
|
|
48
|
+
return (value ?? '')
|
|
49
|
+
.split('~')
|
|
50
|
+
.map((pair) => pair.split('.'))
|
|
51
|
+
.filter(([hint, secret, ...rest]) => HINT_PATTERN.test(hint) && TOKEN_PATTERN.test(secret ?? '') && !rest.length)
|
|
52
|
+
.slice(0, PENDING_LINKS)
|
|
53
|
+
.map(([hint, secret]) => ({ hint, secret }));
|
|
54
|
+
}
|
|
55
|
+
function writePending(links) {
|
|
56
|
+
return links.map(({ hint, secret }) => `${hint}.${secret}`).join('~');
|
|
57
|
+
}
|
|
40
58
|
/**
|
|
41
59
|
* Passwordless sign-in links: 256-bit single-use tokens, stored hashed,
|
|
42
60
|
* short-lived, and bound to the browser that requested them.
|
|
@@ -49,7 +67,9 @@ function hintOf(token) {
|
|
|
49
67
|
* site's page must not start a link here), and sets an `HttpOnly`,
|
|
50
68
|
* `SameSite=Lax` cookie, `__Host-magic_link_tx`, holding a secret that no
|
|
51
69
|
* link carries; the store keys the link by the token and that secret
|
|
52
|
-
* together, so `consume()` finds it only with the cookie. The
|
|
70
|
+
* together, so `consume()` finds it only with the cookie. The cookie holds
|
|
71
|
+
* the secrets of the last five links the browser requested, so a "resend"
|
|
72
|
+
* leaves the link before it usable there. The `__Host-`
|
|
53
73
|
* prefix keeps sibling subdomains from planting one. So the link's page
|
|
54
74
|
* must be on the same site as the API, as the session cookie requires
|
|
55
75
|
* anyway, and a link forwarded to another browser or device, or read from
|
|
@@ -106,7 +126,10 @@ let MagicLinkService = class MagicLinkService {
|
|
|
106
126
|
});
|
|
107
127
|
let cookie;
|
|
108
128
|
if (binding) {
|
|
109
|
-
|
|
129
|
+
// The links this browser requested before stay usable here, the oldest dropped past the cap.
|
|
130
|
+
const hint = hintOf(token);
|
|
131
|
+
const before = readPending(this.pendingCookie(this.scope.exchange()?.request)).filter((link) => link.hint !== hint);
|
|
132
|
+
cookie = this.txCookie(writePending([{ hint, secret: binding }, ...before].slice(0, PENDING_LINKS)), this.ttl / 1000);
|
|
110
133
|
this.setCookie(cookie);
|
|
111
134
|
}
|
|
112
135
|
const url = new URL(options.url);
|
|
@@ -131,23 +154,27 @@ let MagicLinkService = class MagicLinkService {
|
|
|
131
154
|
return this.refuse('unknown');
|
|
132
155
|
}
|
|
133
156
|
let binding;
|
|
157
|
+
let pending = [];
|
|
158
|
+
let link;
|
|
134
159
|
if (this.bindToBrowser) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
// The hint names the link this browser requested; anyone holding the link can compute it, so it
|
|
160
|
+
pending = readPending(this.pendingCookie(request ?? this.scope.exchange()?.request));
|
|
161
|
+
// The hint names a link this browser requested; anyone holding the link can compute it, so it
|
|
138
162
|
// only tells a link opened elsewhere from a bad one. The secret, which no link carries, is what
|
|
139
163
|
// the link is stored under: a leaked or forwarded link finds nothing without it. On a refusal
|
|
140
|
-
// here the cookie stays (it
|
|
164
|
+
// here the cookie stays (it holds the links this browser did request), and nothing is looked
|
|
141
165
|
// up: a link was presented, not proved.
|
|
142
|
-
|
|
166
|
+
const hint = hintOf(token);
|
|
167
|
+
link = pending.find((candidate) => safeEqual(candidate.hint, hint));
|
|
168
|
+
if (!link) {
|
|
143
169
|
this.events.emit({ type: 'magic-link-refused', reason: 'not-this-browser' });
|
|
144
170
|
throw new MagicLinkError();
|
|
145
171
|
}
|
|
146
|
-
binding = secret;
|
|
172
|
+
binding = link.secret;
|
|
147
173
|
}
|
|
148
174
|
const record = await this.storage.magicLinks.consumeMagicLink(linkId(token, binding));
|
|
149
|
-
// This
|
|
150
|
-
|
|
175
|
+
// This link is settled either way: its secret goes, and the cookie with it when it held no other.
|
|
176
|
+
const rest = writePending(pending.filter((candidate) => candidate !== link));
|
|
177
|
+
this.setCookie(this.txCookie(rest, rest ? this.ttl / 1000 : 0));
|
|
151
178
|
if (!record) {
|
|
152
179
|
return this.refuse('unknown');
|
|
153
180
|
}
|
|
@@ -185,6 +212,9 @@ let MagicLinkService = class MagicLinkService {
|
|
|
185
212
|
this.events.emit({ type: 'magic-link-refused', reason, ...(email && { email }) });
|
|
186
213
|
return null;
|
|
187
214
|
}
|
|
215
|
+
pendingCookie(request) {
|
|
216
|
+
return readCookie(firstHeader(request?.headers, 'cookie'), this.txCookieName);
|
|
217
|
+
}
|
|
188
218
|
txCookie(value, maxAge) {
|
|
189
219
|
return serializeCookie(this.txCookieName, value, { ...this.options?.cookie, sameSite: 'lax', maxAge });
|
|
190
220
|
}
|
|
@@ -82,6 +82,7 @@ export declare class OidcService {
|
|
|
82
82
|
private feature;
|
|
83
83
|
/** A fully signed-in session (second factor done, if any) on this request. */
|
|
84
84
|
private currentSession;
|
|
85
|
+
/** `oidc.callbackUrl` for this request, with the provider's name in it. */
|
|
85
86
|
private callbackUrl;
|
|
86
87
|
private txCookie;
|
|
87
88
|
private now;
|
|
@@ -79,7 +79,9 @@ let OidcService = class OidcService {
|
|
|
79
79
|
this.clients = new Map();
|
|
80
80
|
this.options = options?.oidc;
|
|
81
81
|
if (this.options) {
|
|
82
|
-
|
|
82
|
+
if (typeof this.options.callbackUrl !== 'function') {
|
|
83
|
+
assertCallbackUrl(this.options.callbackUrl);
|
|
84
|
+
}
|
|
83
85
|
assertProviderCredentials(this.options.providers);
|
|
84
86
|
}
|
|
85
87
|
this.transactionTtl = durationOr(this.options?.transactionTtl, '10m');
|
|
@@ -120,7 +122,7 @@ let OidcService = class OidcService {
|
|
|
120
122
|
linking = { userId: session.userId, sessionId: session.id };
|
|
121
123
|
}
|
|
122
124
|
const { url, transaction, binding } = await this.client(provider)
|
|
123
|
-
.authorizationRequest(this.callbackUrl(provider), safeRedirectPath(redirectTo), this.transactionTtl)
|
|
125
|
+
.authorizationRequest(await this.callbackUrl(provider, req), safeRedirectPath(redirectTo), this.transactionTtl)
|
|
124
126
|
.catch(toHttp);
|
|
125
127
|
await this.storage.oidcStates.saveOidcState({ ...transaction, ...(linking && { link: linking }) });
|
|
126
128
|
return this.redirect(exchange?.response, url, [this.txCookie(binding, this.transactionTtl / 1000)]);
|
|
@@ -146,7 +148,10 @@ let OidcService = class OidcService {
|
|
|
146
148
|
if (!transaction || transaction.provider !== provider || hasExpired(transaction.expiresAt, this.now())) {
|
|
147
149
|
throw new BadRequestException('unknown or expired login');
|
|
148
150
|
}
|
|
149
|
-
|
|
151
|
+
// Asked again rather than stored with the login: the cookie keeps the callback on the login's host,
|
|
152
|
+
// and a function that answers otherwise gets the code refused by the provider, not accepted.
|
|
153
|
+
const callbackUrl = await this.callbackUrl(provider, req);
|
|
154
|
+
const result = await this.client(provider).callback(query, transaction, callbackUrl).catch(toHttp);
|
|
150
155
|
const location = transaction.redirectTo ?? options.redirectAfterLogin ?? '/';
|
|
151
156
|
if (transaction.link) {
|
|
152
157
|
// The session that asked to link must still be the one on this browser.
|
|
@@ -194,8 +199,14 @@ let OidcService = class OidcService {
|
|
|
194
199
|
const session = await this.sessions.validate(this.sessions.tokenFrom(request));
|
|
195
200
|
return session && session.mfa !== 'pending' ? session : null;
|
|
196
201
|
}
|
|
197
|
-
callbackUrl
|
|
198
|
-
|
|
202
|
+
/** `oidc.callbackUrl` for this request, with the provider's name in it. */
|
|
203
|
+
async callbackUrl(provider, request) {
|
|
204
|
+
const { callbackUrl } = this.feature().options;
|
|
205
|
+
const url = typeof callbackUrl === 'function' ? await callbackUrl(request) : callbackUrl;
|
|
206
|
+
if (typeof callbackUrl === 'function') {
|
|
207
|
+
assertCallbackUrl(url, 'the `oidc.callbackUrl` function must return');
|
|
208
|
+
}
|
|
209
|
+
return url.replaceAll(':provider', encodeURIComponent(provider));
|
|
199
210
|
}
|
|
200
211
|
txCookie(value, maxAge) {
|
|
201
212
|
return serializeCookie(this.txCookieName, value, { ...this.options?.cookie, sameSite: 'lax', maxAge });
|
|
@@ -216,8 +227,11 @@ OidcService = __decorate([
|
|
|
216
227
|
HttpAdapterHost])
|
|
217
228
|
], OidcService);
|
|
218
229
|
export { OidcService };
|
|
219
|
-
/**
|
|
220
|
-
|
|
230
|
+
/**
|
|
231
|
+
* `oidc.callbackUrl`, checked at startup (or each URL its function returns,
|
|
232
|
+
* when it returns it): an absolute http(s) URL.
|
|
233
|
+
*/
|
|
234
|
+
function assertCallbackUrl(value, must = '`oidc.callbackUrl` must be') {
|
|
221
235
|
let url;
|
|
222
236
|
try {
|
|
223
237
|
url = typeof value === 'string' ? new URL(value.replaceAll(':provider', 'provider')) : undefined;
|
|
@@ -226,7 +240,7 @@ function assertCallbackUrl(value) {
|
|
|
226
240
|
url = undefined;
|
|
227
241
|
}
|
|
228
242
|
if (!url || (url.protocol !== 'https:' && url.protocol !== 'http:')) {
|
|
229
|
-
throw new Error(
|
|
243
|
+
throw new Error(`OidcService: ${must} the absolute URL of your callback route, with \`:provider\` where the ` +
|
|
230
244
|
`provider's name goes, e.g. 'https://app.example.com/auth/oidc/:provider/callback'. Got ${JSON.stringify(value)}.`);
|
|
231
245
|
}
|
|
232
246
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nestjs/authentication",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Nest - modern, fast, powerful node.js web framework (@authentication)",
|
|
5
5
|
"author": "Kamil Mysliwiec",
|
|
6
6
|
"license": "MIT",
|
|
@@ -46,39 +46,39 @@
|
|
|
46
46
|
"@electric-sql/pglite": "0.5.8",
|
|
47
47
|
"@electric-sql/pglite-socket": "0.2.11",
|
|
48
48
|
"@nestjs/apollo": "14.0.1",
|
|
49
|
-
"@nestjs/authorization": "0.0
|
|
49
|
+
"@nestjs/authorization": "0.1.0",
|
|
50
50
|
"@nestjs/common": "12.1.2",
|
|
51
51
|
"@nestjs/core": "12.1.2",
|
|
52
52
|
"@nestjs/drizzle": "0.0.1",
|
|
53
53
|
"@nestjs/graphql": "14.0.1",
|
|
54
|
-
"@nestjs/idempotency": "0.0.
|
|
54
|
+
"@nestjs/idempotency": "0.0.2",
|
|
55
55
|
"@nestjs/mail": "0.0.1",
|
|
56
56
|
"@nestjs/microservices": "12.1.2",
|
|
57
57
|
"@nestjs/platform-express": "12.1.2",
|
|
58
58
|
"@nestjs/platform-fastify": "12.1.2",
|
|
59
59
|
"@nestjs/platform-ws": "12.1.2",
|
|
60
|
-
"@nestjs/resilience": "0.0.
|
|
60
|
+
"@nestjs/resilience": "0.0.2",
|
|
61
61
|
"@nestjs/testing": "12.1.2",
|
|
62
62
|
"@nestjs/throttler": "6.7.1",
|
|
63
63
|
"@nestjs/websockets": "12.1.2",
|
|
64
|
-
"@types/node": "24.19.
|
|
64
|
+
"@types/node": "24.19.2",
|
|
65
65
|
"@types/pg": "8.23.1",
|
|
66
66
|
"@types/supertest": "7.2.1",
|
|
67
67
|
"@types/ws": "8.18.2",
|
|
68
|
-
"drizzle-orm": "0.45.
|
|
68
|
+
"drizzle-orm": "0.45.4",
|
|
69
69
|
"graphql": "16.14.2",
|
|
70
70
|
"husky": "9.1.7",
|
|
71
71
|
"lint-staged": "17.6.0",
|
|
72
72
|
"oxlint": "1.87.0",
|
|
73
73
|
"pg": "8.23.1",
|
|
74
|
-
"prettier": "3.9.
|
|
74
|
+
"prettier": "3.9.10",
|
|
75
75
|
"reflect-metadata": "0.2.2",
|
|
76
76
|
"release-it": "21.1.1",
|
|
77
77
|
"rxjs": "7.8.2",
|
|
78
78
|
"supertest": "7.3.1",
|
|
79
79
|
"typeorm": "1.1.2",
|
|
80
80
|
"typescript": "7.0.2",
|
|
81
|
-
"vite": "8.3.
|
|
81
|
+
"vite": "8.3.4",
|
|
82
82
|
"vitest": "5.0.3",
|
|
83
83
|
"ws": "8.22.0"
|
|
84
84
|
},
|