@nestjs/authentication 0.0.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/LICENSE +23 -0
- package/README.md +50 -0
- package/dist/account/email-verification.handler.d.ts +23 -0
- package/dist/account/email-verification.handler.js +17 -0
- package/dist/account/email-verification.service.d.ts +46 -0
- package/dist/account/email-verification.service.js +111 -0
- package/dist/account/email.util.d.ts +14 -0
- package/dist/account/email.util.js +28 -0
- package/dist/account/in-memory-email-token.store.d.ts +12 -0
- package/dist/account/in-memory-email-token.store.js +60 -0
- package/dist/account/password-reset.handler.d.ts +19 -0
- package/dist/account/password-reset.handler.js +9 -0
- package/dist/account/password-reset.service.d.ts +69 -0
- package/dist/account/password-reset.service.js +204 -0
- package/dist/authentication.constants.d.ts +13 -0
- package/dist/authentication.constants.js +13 -0
- package/dist/authentication.module-definition.d.ts +21 -0
- package/dist/authentication.module-definition.js +147 -0
- package/dist/authentication.module.d.ts +34 -0
- package/dist/authentication.module.js +139 -0
- package/dist/context/authentication-scope.service.d.ts +39 -0
- package/dist/context/authentication-scope.service.js +64 -0
- package/dist/context/authentication.context.d.ts +28 -0
- package/dist/context/authentication.context.js +58 -0
- package/dist/context/index.d.ts +2 -0
- package/dist/context/index.js +2 -0
- package/dist/decorators/authenticate.decorator.d.ts +10 -0
- package/dist/decorators/authenticate.decorator.js +18 -0
- package/dist/decorators/current-session.decorator.d.ts +2 -0
- package/dist/decorators/current-session.decorator.js +6 -0
- package/dist/decorators/current-user.decorator.d.ts +6 -0
- package/dist/decorators/current-user.decorator.js +11 -0
- package/dist/decorators/index.d.ts +4 -0
- package/dist/decorators/index.js +4 -0
- package/dist/decorators/public.decorator.d.ts +5 -0
- package/dist/decorators/public.decorator.js +6 -0
- package/dist/errors/authentication.error.d.ts +27 -0
- package/dist/errors/authentication.error.js +33 -0
- package/dist/errors/index.d.ts +7 -0
- package/dist/errors/index.js +7 -0
- package/dist/errors/jwt.error.d.ts +9 -0
- package/dist/errors/jwt.error.js +12 -0
- package/dist/errors/magic-link.error.d.ts +18 -0
- package/dist/errors/magic-link.error.js +21 -0
- package/dist/errors/mfa-already-enrolled.error.d.ts +14 -0
- package/dist/errors/mfa-already-enrolled.error.js +17 -0
- package/dist/errors/oidc.error.d.ts +15 -0
- package/dist/errors/oidc.error.js +13 -0
- package/dist/errors/refresh-token.error.d.ts +10 -0
- package/dist/errors/refresh-token.error.js +12 -0
- package/dist/errors/secret-decryption.error.d.ts +3 -0
- package/dist/errors/secret-decryption.error.js +6 -0
- package/dist/events/authentication-events.interface.d.ts +121 -0
- package/dist/events/authentication-events.interface.js +1 -0
- package/dist/events/authentication-events.service.d.ts +19 -0
- package/dist/events/authentication-events.service.js +39 -0
- package/dist/events/authentication.channels.d.ts +4 -0
- package/dist/events/authentication.channels.js +11 -0
- package/dist/events/index.d.ts +3 -0
- package/dist/events/index.js +3 -0
- package/dist/guards/authentication.guard.d.ts +57 -0
- package/dist/guards/authentication.guard.js +171 -0
- package/dist/guards/index.d.ts +1 -0
- package/dist/guards/index.js +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.js +52 -0
- package/dist/interceptors/authentication-scope.interceptor.d.ts +20 -0
- package/dist/interceptors/authentication-scope.interceptor.js +48 -0
- package/dist/interceptors/index.d.ts +1 -0
- package/dist/interceptors/index.js +1 -0
- package/dist/interfaces/api-key.interface.d.ts +41 -0
- package/dist/interfaces/api-key.interface.js +1 -0
- package/dist/interfaces/authenticate-options.interface.d.ts +31 -0
- package/dist/interfaces/authenticate-options.interface.js +1 -0
- package/dist/interfaces/authentication-error-options.interface.d.ts +8 -0
- package/dist/interfaces/authentication-error-options.interface.js +1 -0
- package/dist/interfaces/authentication-module-options.interface.d.ts +58 -0
- package/dist/interfaces/authentication-module-options.interface.js +1 -0
- package/dist/interfaces/authentication-registry.interface.d.ts +41 -0
- package/dist/interfaces/authentication-registry.interface.js +1 -0
- package/dist/interfaces/authentication-result.interface.d.ts +25 -0
- package/dist/interfaces/authentication-result.interface.js +1 -0
- package/dist/interfaces/authentication-storage.interface.d.ts +29 -0
- package/dist/interfaces/authentication-storage.interface.js +1 -0
- package/dist/interfaces/duration.interface.d.ts +2 -0
- package/dist/interfaces/duration.interface.js +1 -0
- package/dist/interfaces/email-token-store.interface.d.ts +52 -0
- package/dist/interfaces/email-token-store.interface.js +1 -0
- package/dist/interfaces/email-verification.interface.d.ts +18 -0
- package/dist/interfaces/email-verification.interface.js +1 -0
- package/dist/interfaces/index.d.ts +27 -0
- package/dist/interfaces/index.js +27 -0
- package/dist/interfaces/jwt-options.interface.d.ts +68 -0
- package/dist/interfaces/jwt-options.interface.js +1 -0
- package/dist/interfaces/jwt.interface.d.ts +36 -0
- package/dist/interfaces/jwt.interface.js +1 -0
- package/dist/interfaces/magic-link-store.interface.d.ts +36 -0
- package/dist/interfaces/magic-link-store.interface.js +1 -0
- package/dist/interfaces/magic-link.interface.d.ts +55 -0
- package/dist/interfaces/magic-link.interface.js +1 -0
- package/dist/interfaces/mfa-options.interface.d.ts +44 -0
- package/dist/interfaces/mfa-options.interface.js +1 -0
- package/dist/interfaces/mfa-store.interface.d.ts +70 -0
- package/dist/interfaces/mfa-store.interface.js +1 -0
- package/dist/interfaces/oidc-provider.interface.d.ts +56 -0
- package/dist/interfaces/oidc-provider.interface.js +1 -0
- package/dist/interfaces/oidc-state-store.interface.d.ts +25 -0
- package/dist/interfaces/oidc-state-store.interface.js +1 -0
- package/dist/interfaces/oidc.interface.d.ts +84 -0
- package/dist/interfaces/oidc.interface.js +1 -0
- package/dist/interfaces/password-hasher-options.interface.d.ts +17 -0
- package/dist/interfaces/password-hasher-options.interface.js +1 -0
- package/dist/interfaces/password-reset.interface.d.ts +49 -0
- package/dist/interfaces/password-reset.interface.js +1 -0
- package/dist/interfaces/refresh-token-options.interface.d.ts +10 -0
- package/dist/interfaces/refresh-token-options.interface.js +1 -0
- package/dist/interfaces/refresh-token-store.interface.d.ts +61 -0
- package/dist/interfaces/refresh-token-store.interface.js +1 -0
- package/dist/interfaces/session-store.interface.d.ts +53 -0
- package/dist/interfaces/session-store.interface.js +1 -0
- package/dist/interfaces/session.interface.d.ts +50 -0
- package/dist/interfaces/session.interface.js +1 -0
- package/dist/interfaces/sign-in-options.interface.d.ts +9 -0
- package/dist/interfaces/sign-in-options.interface.js +1 -0
- package/dist/interfaces/token.interface.d.ts +30 -0
- package/dist/interfaces/token.interface.js +1 -0
- package/dist/jwt/amr.util.d.ts +9 -0
- package/dist/jwt/amr.util.js +11 -0
- package/dist/jwt/in-memory-refresh-token.store.d.ts +29 -0
- package/dist/jwt/in-memory-refresh-token.store.js +67 -0
- package/dist/jwt/jwks.client.d.ts +34 -0
- package/dist/jwt/jwks.client.js +154 -0
- package/dist/jwt/jws.util.d.ts +45 -0
- package/dist/jwt/jws.util.js +282 -0
- package/dist/jwt/jwt-bearer.provider.d.ts +48 -0
- package/dist/jwt/jwt-bearer.provider.js +126 -0
- package/dist/jwt/jwt-signer.service.d.ts +19 -0
- package/dist/jwt/jwt-signer.service.js +36 -0
- package/dist/jwt/jwt-verifier.service.d.ts +22 -0
- package/dist/jwt/jwt-verifier.service.js +109 -0
- package/dist/jwt/token.service.d.ts +81 -0
- package/dist/jwt/token.service.js +230 -0
- package/dist/magic-link/in-memory-magic-link.store.d.ts +12 -0
- package/dist/magic-link/in-memory-magic-link.store.js +45 -0
- package/dist/magic-link/magic-link.handler.d.ts +25 -0
- package/dist/magic-link/magic-link.handler.js +14 -0
- package/dist/magic-link/magic-link.service.d.ts +79 -0
- package/dist/magic-link/magic-link.service.js +215 -0
- package/dist/mfa/in-memory-mfa.store.d.ts +25 -0
- package/dist/mfa/in-memory-mfa.store.js +73 -0
- package/dist/mfa/mfa.service.d.ts +104 -0
- package/dist/mfa/mfa.service.js +346 -0
- package/dist/mfa/otp.util.d.ts +7 -0
- package/dist/mfa/otp.util.js +52 -0
- package/dist/mfa/secret-cipher.service.d.ts +28 -0
- package/dist/mfa/secret-cipher.service.js +106 -0
- package/dist/oidc/in-memory-oidc-state.store.d.ts +13 -0
- package/dist/oidc/in-memory-oidc-state.store.js +45 -0
- package/dist/oidc/oidc-account.resolver.d.ts +23 -0
- package/dist/oidc/oidc-account.resolver.js +16 -0
- package/dist/oidc/oidc.client.d.ts +44 -0
- package/dist/oidc/oidc.client.js +286 -0
- package/dist/oidc/oidc.presets.d.ts +24 -0
- package/dist/oidc/oidc.presets.js +53 -0
- package/dist/oidc/oidc.service.d.ts +88 -0
- package/dist/oidc/oidc.service.js +259 -0
- package/dist/providers/api-key.provider.d.ts +51 -0
- package/dist/providers/api-key.provider.js +93 -0
- package/dist/providers/authentication.provider.d.ts +40 -0
- package/dist/providers/authentication.provider.js +33 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.js +2 -0
- package/dist/services/authentication-registry.service.d.ts +75 -0
- package/dist/services/authentication-registry.service.js +235 -0
- package/dist/services/index.d.ts +3 -0
- package/dist/services/index.js +3 -0
- package/dist/services/password-hasher.service.d.ts +47 -0
- package/dist/services/password-hasher.service.js +170 -0
- package/dist/services/ws-authenticator.service.d.ts +38 -0
- package/dist/services/ws-authenticator.service.js +92 -0
- package/dist/session/cookies.util.d.ts +34 -0
- package/dist/session/cookies.util.js +82 -0
- package/dist/session/in-memory-session.store.d.ts +33 -0
- package/dist/session/in-memory-session.store.js +60 -0
- package/dist/session/session-cookie.provider.d.ts +36 -0
- package/dist/session/session-cookie.provider.js +58 -0
- package/dist/session/session.service.d.ts +97 -0
- package/dist/session/session.service.js +208 -0
- package/dist/session/sign-in.service.d.ts +87 -0
- package/dist/session/sign-in.service.js +206 -0
- package/dist/storage/authentication.storage.d.ts +130 -0
- package/dist/storage/authentication.storage.js +350 -0
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +1 -0
- package/dist/testing/index.d.ts +39 -0
- package/dist/testing/index.js +531 -0
- package/dist/utils/api-key.util.d.ts +10 -0
- package/dist/utils/api-key.util.js +10 -0
- package/dist/utils/auth-state.util.d.ts +54 -0
- package/dist/utils/auth-state.util.js +209 -0
- package/dist/utils/bearer.util.d.ts +9 -0
- package/dist/utils/bearer.util.js +21 -0
- package/dist/utils/cross-origin.util.d.ts +29 -0
- package/dist/utils/cross-origin.util.js +90 -0
- package/dist/utils/crypto.util.d.ts +19 -0
- package/dist/utils/crypto.util.js +38 -0
- package/dist/utils/duration.util.d.ts +9 -0
- package/dist/utils/duration.util.js +44 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/options.util.d.ts +20 -0
- package/dist/utils/options.util.js +44 -0
- package/dist/utils/transport-errors.util.d.ts +33 -0
- package/dist/utils/transport-errors.util.js +70 -0
- package/package.json +108 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { ForbiddenException, Injectable, Optional } from '@nestjs/common';
|
|
14
|
+
import { HttpAdapterHost } from '@nestjs/core';
|
|
15
|
+
import { AuthenticationScope } from '../context/authentication-scope.service.js';
|
|
16
|
+
import { AuthenticationEvents } from '../events/authentication-events.service.js';
|
|
17
|
+
import { TokenService } from '../jwt/token.service.js';
|
|
18
|
+
import { MfaService } from '../mfa/mfa.service.js';
|
|
19
|
+
import { sha256 } from '../utils/crypto.util.js';
|
|
20
|
+
import { SessionService } from './session.service.js';
|
|
21
|
+
/**
|
|
22
|
+
* The browser's side of signing in. Called from an HTTP handler (or a
|
|
23
|
+
* GraphQL resolver whose context has `req` and `res`), each method reads
|
|
24
|
+
* this browser's session cookie from the request and sets the new one on
|
|
25
|
+
* the response, on Express and Fastify alike. Elsewhere, nothing is read or
|
|
26
|
+
* set: send the returned `cookie` yourself.
|
|
27
|
+
*
|
|
28
|
+
* `signIn()` is the one place a first factor (password, magic link, OIDC)
|
|
29
|
+
* turns into a session:
|
|
30
|
+
* - a sign-in posted from another origin's page is refused with a 403
|
|
31
|
+
* (login CSRF: signing the victim's browser in to the attacker's
|
|
32
|
+
* account), by the same rule as `app.enableCsrfProtection()`;
|
|
33
|
+
* - the browser's previous session is deleted (session fixation defence);
|
|
34
|
+
* - users with a confirmed authenticator get an `mfa: 'pending'` session,
|
|
35
|
+
* which is not signed in anywhere until `completeMfa()` verifies a code.
|
|
36
|
+
*/
|
|
37
|
+
let SignInService = class SignInService {
|
|
38
|
+
constructor(sessions, mfa, tokens, scope = new AuthenticationScope(), adapterHost, events = new AuthenticationEvents()) {
|
|
39
|
+
this.sessions = sessions;
|
|
40
|
+
this.mfa = mfa;
|
|
41
|
+
this.tokens = tokens;
|
|
42
|
+
this.scope = scope;
|
|
43
|
+
this.adapterHost = adapterHost;
|
|
44
|
+
this.events = events;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Signs the user in on this browser. Throws a `ForbiddenException` for a
|
|
48
|
+
* request that changes state from another origin than the app's own and
|
|
49
|
+
* `session.trustedOrigins`.
|
|
50
|
+
*/
|
|
51
|
+
async signIn(userId, { method, metadata } = {}) {
|
|
52
|
+
const exchange = this.scope.exchange();
|
|
53
|
+
this.refuseCrossOrigin(exchange?.request);
|
|
54
|
+
const mfa = (await this.mfa.isEnrolled(userId)) ? 'pending' : undefined;
|
|
55
|
+
const stored = { ...this.sessions.metadataFor(exchange?.request), ...metadata };
|
|
56
|
+
const issued = await this.sessions.create(userId, {
|
|
57
|
+
mfa,
|
|
58
|
+
metadata: Object.keys(stored).length ? stored : undefined,
|
|
59
|
+
replacing: this.sessions.tokenFrom(exchange?.request),
|
|
60
|
+
});
|
|
61
|
+
this.setCookie(exchange, issued.cookie);
|
|
62
|
+
this.events.emit({
|
|
63
|
+
type: 'sign-in',
|
|
64
|
+
userId,
|
|
65
|
+
sessionId: issued.session.id,
|
|
66
|
+
...(method && { method }),
|
|
67
|
+
...(mfa && { mfa }),
|
|
68
|
+
...(issued.session.metadata && { metadata: issued.session.metadata }),
|
|
69
|
+
});
|
|
70
|
+
return issued;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Completes the second factor of this browser's session with a TOTP code
|
|
74
|
+
* or a recovery code, and rotates the session to `mfa: 'verified'` under a
|
|
75
|
+
* new id. `null` when the browser has no session or the code is wrong. A
|
|
76
|
+
* request with neither counts nothing against the user's lockout, as
|
|
77
|
+
* `TokenService.issue()` without a `secondFactor` doesn't.
|
|
78
|
+
*/
|
|
79
|
+
async completeMfa({ code, recoveryCode }) {
|
|
80
|
+
if (!code && !recoveryCode) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const exchange = this.scope.exchange();
|
|
84
|
+
const session = await this.sessions.validate(this.sessions.tokenFrom(exchange?.request));
|
|
85
|
+
if (!session) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const verified = recoveryCode
|
|
89
|
+
? await this.mfa.verifyRecoveryCode(session.userId, recoveryCode)
|
|
90
|
+
: await this.mfa.verifyTotp(session.userId, code);
|
|
91
|
+
if (!verified) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
// A revocation that took the session meanwhile wins: no verified session comes of it.
|
|
95
|
+
const issued = await this.sessions.rotate(session, { mfa: 'verified' });
|
|
96
|
+
if (issued) {
|
|
97
|
+
this.setCookie(exchange, issued.cookie);
|
|
98
|
+
}
|
|
99
|
+
return issued;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Confirms the user's new authenticator with a code from it
|
|
103
|
+
* (`MfaService.confirm()`), and, when this browser holds a session of the
|
|
104
|
+
* user, rotates it to `mfa: 'verified'` under a new id: the code proved
|
|
105
|
+
* this browser has the authenticator, so the user isn't asked for another
|
|
106
|
+
* code until their next sign-in. Without such a session (a token client,
|
|
107
|
+
* another user's session), it only confirms. `false` when the code is
|
|
108
|
+
* wrong, and nothing changes.
|
|
109
|
+
*/
|
|
110
|
+
async confirmMfa(userId, code) {
|
|
111
|
+
if (!(await this.mfa.confirm(userId, code))) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
const exchange = this.scope.exchange();
|
|
115
|
+
const session = await this.sessions.validate(this.sessions.tokenFrom(exchange?.request));
|
|
116
|
+
if (session?.userId === userId) {
|
|
117
|
+
const issued = await this.sessions.rotate(session, { mfa: 'verified' });
|
|
118
|
+
if (issued) {
|
|
119
|
+
this.setCookie(exchange, issued.cookie);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Gives this browser's session a new id, keeping its user, expiry and
|
|
126
|
+
* second factor, and updates the cookie. Call it on privilege changes: a
|
|
127
|
+
* new password, a new role. `null` when the browser has no session, or
|
|
128
|
+
* lost it meanwhile (revoked, or rotated by another request).
|
|
129
|
+
*/
|
|
130
|
+
async rotateSession() {
|
|
131
|
+
const exchange = this.scope.exchange();
|
|
132
|
+
const session = await this.sessions.validate(this.sessions.tokenFrom(exchange?.request));
|
|
133
|
+
if (!session) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
const issued = await this.sessions.rotate(session);
|
|
137
|
+
if (issued) {
|
|
138
|
+
this.setCookie(exchange, issued.cookie);
|
|
139
|
+
}
|
|
140
|
+
return issued;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Ends this browser's session, pending or not, and clears its cookie.
|
|
144
|
+
* `false` when the browser had no live session (a bearer-token client, an
|
|
145
|
+
* expired cookie).
|
|
146
|
+
*/
|
|
147
|
+
async signOut() {
|
|
148
|
+
const exchange = this.scope.exchange();
|
|
149
|
+
const token = this.sessions.tokenFrom(exchange?.request);
|
|
150
|
+
if (!token) {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
const session = await this.sessions.validate(token);
|
|
154
|
+
this.setCookie(exchange, this.sessions.clearCookie());
|
|
155
|
+
// Deleted whatever this instance makes of it: idle here, it may still be live for another
|
|
156
|
+
// instance (its clock, or another idleTtl during a rolling deploy).
|
|
157
|
+
await this.sessions.discard(sha256(token));
|
|
158
|
+
if (!session) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
this.events.emit({ type: 'sign-out', userId: session.userId, sessionId: session.id });
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Ends every session and refresh-token family of the user, and clears
|
|
166
|
+
* this browser's cookie if it was one of them. API keys live in your own
|
|
167
|
+
* table: revoke those yourself.
|
|
168
|
+
*/
|
|
169
|
+
async signOutEverywhere(userId) {
|
|
170
|
+
const exchange = this.scope.exchange();
|
|
171
|
+
const own = await this.sessions.validate(this.sessions.tokenFrom(exchange?.request));
|
|
172
|
+
await this.sessions.revokeAll(userId);
|
|
173
|
+
await this.tokens.revokeAll(userId);
|
|
174
|
+
if (own?.userId === userId) {
|
|
175
|
+
this.setCookie(exchange, this.sessions.clearCookie());
|
|
176
|
+
}
|
|
177
|
+
this.events.emit({ type: 'sign-out', userId, everywhere: true });
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* @internal The 403 `signIn()` answers a request that changes state from
|
|
181
|
+
* another origin than the app's own and `session.trustedOrigins` with.
|
|
182
|
+
* What binds a sign-in to a browser (a magic link's `create()`) checks it
|
|
183
|
+
* too: another site's page must not start one in the victim's browser.
|
|
184
|
+
*/
|
|
185
|
+
refuseCrossOrigin(request) {
|
|
186
|
+
if (request && this.sessions.isCrossOriginWrite(request)) {
|
|
187
|
+
throw new ForbiddenException('Cross-origin sign-in refused');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
setCookie(exchange, cookie) {
|
|
191
|
+
if (exchange?.response) {
|
|
192
|
+
this.adapterHost?.httpAdapter?.appendHeader(exchange.response, 'Set-Cookie', cookie);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
SignInService = __decorate([
|
|
197
|
+
Injectable(),
|
|
198
|
+
__param(4, Optional()),
|
|
199
|
+
__metadata("design:paramtypes", [SessionService,
|
|
200
|
+
MfaService,
|
|
201
|
+
TokenService,
|
|
202
|
+
AuthenticationScope,
|
|
203
|
+
HttpAdapterHost,
|
|
204
|
+
AuthenticationEvents])
|
|
205
|
+
], SignInService);
|
|
206
|
+
export { SignInService };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import type { EmailTokenStore } from '../interfaces/email-token-store.interface.js';
|
|
2
|
+
import type { RefreshTokenStore } from '../interfaces/refresh-token-store.interface.js';
|
|
3
|
+
import type { MagicLinkStore } from '../interfaces/magic-link-store.interface.js';
|
|
4
|
+
import type { MfaStore } from '../interfaces/mfa-store.interface.js';
|
|
5
|
+
import type { OidcStateStore } from '../interfaces/oidc-state-store.interface.js';
|
|
6
|
+
import type { SessionStore } from '../interfaces/session-store.interface.js';
|
|
7
|
+
import type { AuthenticationStorageSources, AuthenticationStorageContract, AuthenticationStorageRegisterOptions } from '../interfaces/authentication-storage.interface.js';
|
|
8
|
+
/**
|
|
9
|
+
* @internal What each feature reads or writes, audited against the code
|
|
10
|
+
* paths: the production guard's rule.
|
|
11
|
+
* Any feature that signs someone in reads `mfa`, configured or not: a user
|
|
12
|
+
* may have enrolled an authenticator through another instance, and
|
|
13
|
+
* `MfaService.isEnrolled()` is how a sign-in finds out. Any feature that
|
|
14
|
+
* revokes a user's sign-ins reaches both `sessions` and `refreshTokens`.
|
|
15
|
+
*/
|
|
16
|
+
export declare const CONTRACTS_BY_FEATURE: {
|
|
17
|
+
/**
|
|
18
|
+
* A `SessionCookieProvider` in `providers`: `SessionService` (every
|
|
19
|
+
* request), `SignInService.signIn()` (`isEnrolled()`), `completeMfa()`,
|
|
20
|
+
* and `signOutEverywhere()`, which also revokes the user's refresh-token
|
|
21
|
+
* families.
|
|
22
|
+
*/
|
|
23
|
+
readonly sessionCookie: readonly ["sessions", "refreshTokens", "mfa"];
|
|
24
|
+
/** `accessToken`: `TokenService` (refresh-token families), whose `issue()` checks for an authenticator. */
|
|
25
|
+
readonly accessToken: readonly ["refreshTokens", "mfa"];
|
|
26
|
+
/** `mfa`: enrollment, codes, recovery codes and the lockout. */
|
|
27
|
+
readonly mfa: readonly ["mfa"];
|
|
28
|
+
/** `magicLinkHandler`: pending links, then `SignInService.signIn()`. */
|
|
29
|
+
readonly magicLink: readonly ["sessions", "mfa", "magicLinks"];
|
|
30
|
+
/** `oidcAccountResolver`: logins in progress, the session that links an account, then `SignInService.signIn()`. */
|
|
31
|
+
readonly oidc: readonly ["sessions", "mfa", "oidcStates"];
|
|
32
|
+
/**
|
|
33
|
+
* `passwordResetHandler`: the links; `reset()` revokes every session and
|
|
34
|
+
* refresh-token family of the user, and with `signIn: true` signs in.
|
|
35
|
+
*/
|
|
36
|
+
readonly passwordReset: readonly ["sessions", "refreshTokens", "mfa", "emailTokens"];
|
|
37
|
+
/** `emailVerificationHandler`: the links. */
|
|
38
|
+
readonly emailVerification: readonly ["emailTokens"];
|
|
39
|
+
};
|
|
40
|
+
/** @internal */
|
|
41
|
+
export type AuthenticationFeature = keyof typeof CONTRACTS_BY_FEATURE;
|
|
42
|
+
/** @internal The contracts the features use, in the order messages list them. */
|
|
43
|
+
export declare function contractsUsedBy(features: Iterable<AuthenticationFeature>): AuthenticationStorageContract[];
|
|
44
|
+
/** @internal What the configured features need from storage, computed by the module from its options. */
|
|
45
|
+
export interface AuthenticationStorageRequirements {
|
|
46
|
+
/** The contracts a configured feature uses ({@link contractsUsedBy}): the production guard checks these at startup. */
|
|
47
|
+
contracts: AuthenticationStorageContract[];
|
|
48
|
+
allowInMemoryStorage: boolean;
|
|
49
|
+
}
|
|
50
|
+
interface ContractSpec {
|
|
51
|
+
interfaceName: string;
|
|
52
|
+
/** What is lost with the in-memory default, for the production guard. */
|
|
53
|
+
holds: string;
|
|
54
|
+
methods: readonly string[];
|
|
55
|
+
inMemory: () => object;
|
|
56
|
+
}
|
|
57
|
+
/** @internal Every contract, in the order they are listed in messages. */
|
|
58
|
+
export declare const STORAGE_CONTRACTS: Record<AuthenticationStorageContract, ContractSpec>;
|
|
59
|
+
/** @internal Locks the registry. `AuthenticationModule.onModuleInit()` and the first read call it. */
|
|
60
|
+
export declare const LOCK_STORAGE: unique symbol;
|
|
61
|
+
/**
|
|
62
|
+
* Where the module keeps its state. The app registers its own stores here,
|
|
63
|
+
* from the constructor of an ordinary provider:
|
|
64
|
+
*
|
|
65
|
+
* ```ts
|
|
66
|
+
* @Injectable()
|
|
67
|
+
* export class DrizzleAuthenticationStore implements SessionStore, RefreshTokenStore, MfaStore {
|
|
68
|
+
* constructor(@Inject(DRIZZLE) private readonly db: Database, storage: AuthenticationStorage) {
|
|
69
|
+
* storage.registerSource({ sessions: this, refreshTokens: this, mfa: this });
|
|
70
|
+
* }
|
|
71
|
+
* // ...
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* A contract no source registered uses the in-memory store, so an app that
|
|
76
|
+
* imports the module boots with no storage configured. The registry locks
|
|
77
|
+
* in `AuthenticationModule`'s `onModuleInit` (every provider constructor has
|
|
78
|
+
* run by then), or at the first read of a store if that is earlier (another
|
|
79
|
+
* module's `onModuleInit`): it logs the active sources, and in production
|
|
80
|
+
* refuses to start while a contract a configured feature uses has no
|
|
81
|
+
* source, unless `allowInMemoryStorage` is set. In production, a read of
|
|
82
|
+
* any other contract without a source (an app calling a service outside
|
|
83
|
+
* the features it configured) fails the same way at that read, instead of
|
|
84
|
+
* running on the in-memory default.
|
|
85
|
+
*/
|
|
86
|
+
export declare class AuthenticationStorage {
|
|
87
|
+
private readonly requirements?;
|
|
88
|
+
private static readonly logger;
|
|
89
|
+
private readonly registered;
|
|
90
|
+
private readonly active;
|
|
91
|
+
private locked;
|
|
92
|
+
constructor(requirements?: AuthenticationStorageRequirements | undefined);
|
|
93
|
+
/**
|
|
94
|
+
* Registers stores by contract: `{ sessions: this, refreshTokens: this }`.
|
|
95
|
+
* Call it from the constructor of a singleton provider. Throws, registering
|
|
96
|
+
* nothing, when a store lacks one of its contract's methods, when a
|
|
97
|
+
* contract already has a source (unless `replace` is set: tests,
|
|
98
|
+
* wrappers), and once the registry has locked.
|
|
99
|
+
*/
|
|
100
|
+
registerSource(sources: AuthenticationStorageSources, options?: AuthenticationStorageRegisterOptions): void;
|
|
101
|
+
/** The active session store: the registered one, else the in-memory default. Reading it locks the registry. */
|
|
102
|
+
get sessions(): SessionStore;
|
|
103
|
+
get refreshTokens(): RefreshTokenStore;
|
|
104
|
+
get mfa(): MfaStore;
|
|
105
|
+
get magicLinks(): MagicLinkStore;
|
|
106
|
+
get oidcStates(): OidcStateStore;
|
|
107
|
+
get emailTokens(): EmailTokenStore;
|
|
108
|
+
/**
|
|
109
|
+
* @internal Freezes the sources, logs them, and enforces the production
|
|
110
|
+
* guard (which leaves the registry open): in production, a contract in use
|
|
111
|
+
* with no source fails unless in-memory storage was allowed. `log: false`
|
|
112
|
+
* for the contract suite, which builds a registry per case.
|
|
113
|
+
*/
|
|
114
|
+
[LOCK_STORAGE]({ log }?: {
|
|
115
|
+
log?: boolean;
|
|
116
|
+
}): void;
|
|
117
|
+
private source;
|
|
118
|
+
/**
|
|
119
|
+
* In production, unless `allowInMemoryStorage` is set. A registry built
|
|
120
|
+
* with `new`, outside the module, has no options: it refuses too.
|
|
121
|
+
*/
|
|
122
|
+
private refusesInMemory;
|
|
123
|
+
/**
|
|
124
|
+
* The in-memory default, `DrizzleAuthenticationStore` (one source for every
|
|
125
|
+
* contract), or the contracts in use or registered, by source:
|
|
126
|
+
* `RedisSessionStore (sessions); DrizzleAuthenticationStore (mfa); in-memory (oidcStates)`.
|
|
127
|
+
*/
|
|
128
|
+
private summary;
|
|
129
|
+
}
|
|
130
|
+
export {};
|