@adonisjs/auth 9.0.0-0 → 9.0.0-10

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 (39) hide show
  1. package/build/configure.js +5 -26
  2. package/build/factories/basic_auth_guard_factory.d.ts +12 -0
  3. package/build/factories/basic_auth_guard_factory.js +22 -0
  4. package/build/index.d.ts +1 -2
  5. package/build/index.js +1 -2
  6. package/build/src/auth/auth_manager.d.ts +9 -0
  7. package/build/src/auth/auth_manager.js +13 -0
  8. package/build/src/auth/authenticator.d.ts +45 -0
  9. package/build/src/auth/authenticator.js +74 -0
  10. package/build/src/auth/authenticator_client.d.ts +23 -0
  11. package/build/src/auth/authenticator_client.js +59 -0
  12. package/build/src/auth/errors.d.ts +86 -4
  13. package/build/src/auth/errors.js +189 -5
  14. package/build/src/auth/middleware/initialize_auth_middleware.d.ts +18 -0
  15. package/build/src/auth/middleware/initialize_auth_middleware.js +25 -0
  16. package/build/src/auth/plugins/japa/api_client.d.ts +32 -0
  17. package/build/src/auth/plugins/japa/api_client.js +63 -0
  18. package/build/src/auth/plugins/japa/browser_client.d.ts +25 -0
  19. package/build/src/auth/plugins/japa/browser_client.js +64 -0
  20. package/build/src/auth/types.d.ts +60 -8
  21. package/build/src/core/token.d.ts +4 -1
  22. package/build/src/core/token.js +5 -3
  23. package/build/src/core/token_providers/database.d.ts +1 -1
  24. package/build/src/guards/basic_auth/define_config.d.ts +16 -0
  25. package/build/src/guards/basic_auth/define_config.js +38 -0
  26. package/build/src/guards/basic_auth/guard.d.ts +70 -0
  27. package/build/src/guards/basic_auth/guard.js +193 -0
  28. package/build/src/guards/basic_auth/main.d.ts +2 -0
  29. package/build/{stubs → src/guards/basic_auth}/main.js +2 -2
  30. package/build/src/guards/basic_auth/types.d.ts +40 -0
  31. package/build/src/guards/basic_auth/types.js +9 -0
  32. package/build/src/guards/session/define_config.js +1 -1
  33. package/build/src/guards/session/guard.d.ts +33 -2
  34. package/build/src/guards/session/guard.js +153 -11
  35. package/build/src/guards/session/types.d.ts +19 -3
  36. package/package.json +54 -30
  37. package/build/stubs/config/auth_middleware.stub +0 -12
  38. package/build/stubs/config.stub +0 -35
  39. package/build/stubs/main.d.ts +0 -1
@@ -0,0 +1,70 @@
1
+ import type { HttpContext } from '@adonisjs/core/http';
2
+ import type { EmitterLike } from '@adonisjs/core/types/events';
3
+ import type { BasicAuthGuardEvents } from './types.js';
4
+ import type { GuardContract } from '../../auth/types.js';
5
+ import type { UserProviderContract } from '../../core/types.js';
6
+ import { PROVIDER_REAL_USER, GUARD_KNOWN_EVENTS } from '../../auth/symbols.js';
7
+ /**
8
+ * Implementation of basic auth as an authentication guard
9
+ */
10
+ export declare class BasicAuthGuard<UserProvider extends UserProviderContract<unknown>> implements GuardContract<UserProvider[typeof PROVIDER_REAL_USER]> {
11
+ #private;
12
+ [GUARD_KNOWN_EVENTS]: BasicAuthGuardEvents<UserProvider[typeof PROVIDER_REAL_USER]>;
13
+ /**
14
+ * Driver name of the guard
15
+ */
16
+ driverName: 'basic_auth';
17
+ /**
18
+ * Whether or not the authentication has been attempted
19
+ * during the current request
20
+ */
21
+ authenticationAttempted: boolean;
22
+ /**
23
+ * A boolean to know if the current request has
24
+ * been authenticated
25
+ */
26
+ isAuthenticated: boolean;
27
+ /**
28
+ * Reference to an instance of the authenticated or logged-in
29
+ * user. The value only exists after calling one of the
30
+ * following methods.
31
+ *
32
+ * - authenticate
33
+ *
34
+ * You can use the "getUserOrFail" method to throw an exception if
35
+ * the request is not authenticated.
36
+ */
37
+ user?: UserProvider[typeof PROVIDER_REAL_USER];
38
+ constructor(name: string, ctx: HttpContext, userProvider: UserProvider);
39
+ /**
40
+ * Register an event emitter to listen for global events for
41
+ * authentication lifecycle.
42
+ */
43
+ setEmitter(emitter: EmitterLike<any>): this;
44
+ /**
45
+ * Returns an instance of the authenticated user. Or throws
46
+ * an exception if the request is not authenticated.
47
+ */
48
+ getUserOrFail(): UserProvider[typeof PROVIDER_REAL_USER];
49
+ /**
50
+ * Verifies user credentials and returns an instance of
51
+ * the user or throws "E_INVALID_BASIC_AUTH_CREDENTIALS" exception.
52
+ */
53
+ verifyCredentials(uid: string, password: string): Promise<UserProvider[typeof PROVIDER_REAL_USER]>;
54
+ /**
55
+ * Authenticates the current HTTP request for basic
56
+ * auth credentials
57
+ */
58
+ authenticate(): Promise<UserProvider[typeof PROVIDER_REAL_USER]>;
59
+ /**
60
+ * Silently attempt to authenticate the user.
61
+ *
62
+ * The method returns a boolean indicating if the authentication
63
+ * succeeded or failed.
64
+ */
65
+ check(): Promise<boolean>;
66
+ /**
67
+ * Not support
68
+ */
69
+ authenticateAsClient(_: UserProvider[typeof PROVIDER_REAL_USER]): Promise<never>;
70
+ }
@@ -0,0 +1,193 @@
1
+ /*
2
+ * @adonisjs/auth
3
+ *
4
+ * (c) AdonisJS
5
+ *
6
+ * For the full copyright and license information, please view the LICENSE
7
+ * file that was distributed with this source code.
8
+ */
9
+ import auth from 'basic-auth';
10
+ import { RuntimeException } from '@poppinss/utils';
11
+ import debug from '../../auth/debug.js';
12
+ import { AuthenticationException } from '../../auth/errors.js';
13
+ import { GUARD_KNOWN_EVENTS } from '../../auth/symbols.js';
14
+ /**
15
+ * Implementation of basic auth as an authentication guard
16
+ */
17
+ export class BasicAuthGuard {
18
+ /**
19
+ * A unique name for the guard. It is used while
20
+ * emitting events
21
+ */
22
+ #name;
23
+ /**
24
+ * Reference to the current HTTP context
25
+ */
26
+ #ctx;
27
+ /**
28
+ * Provider to lookup user details
29
+ */
30
+ #userProvider;
31
+ /**
32
+ * Emitter to emit events
33
+ */
34
+ #emitter;
35
+ /**
36
+ * Driver name of the guard
37
+ */
38
+ driverName = 'basic_auth';
39
+ /**
40
+ * Whether or not the authentication has been attempted
41
+ * during the current request
42
+ */
43
+ authenticationAttempted = false;
44
+ /**
45
+ * A boolean to know if the current request has
46
+ * been authenticated
47
+ */
48
+ isAuthenticated = false;
49
+ /**
50
+ * Reference to an instance of the authenticated or logged-in
51
+ * user. The value only exists after calling one of the
52
+ * following methods.
53
+ *
54
+ * - authenticate
55
+ *
56
+ * You can use the "getUserOrFail" method to throw an exception if
57
+ * the request is not authenticated.
58
+ */
59
+ user;
60
+ constructor(name, ctx, userProvider) {
61
+ this.#ctx = ctx;
62
+ this.#name = name;
63
+ this.#userProvider = userProvider;
64
+ }
65
+ /**
66
+ * Notifies about authentication failure and throws the exception
67
+ */
68
+ #authenticationFailed(error) {
69
+ if (this.#emitter) {
70
+ this.#emitter.emit('basic_auth:authentication_failed', {
71
+ ctx: this.#ctx,
72
+ guardName: this.#name,
73
+ error,
74
+ });
75
+ }
76
+ throw error;
77
+ }
78
+ /**
79
+ * Register an event emitter to listen for global events for
80
+ * authentication lifecycle.
81
+ */
82
+ setEmitter(emitter) {
83
+ this.#emitter = emitter;
84
+ return this;
85
+ }
86
+ /**
87
+ * Returns an instance of the authenticated user. Or throws
88
+ * an exception if the request is not authenticated.
89
+ */
90
+ getUserOrFail() {
91
+ if (!this.user) {
92
+ throw AuthenticationException.E_INVALID_BASIC_AUTH_CREDENTIALS();
93
+ }
94
+ return this.user;
95
+ }
96
+ /**
97
+ * Verifies user credentials and returns an instance of
98
+ * the user or throws "E_INVALID_BASIC_AUTH_CREDENTIALS" exception.
99
+ */
100
+ async verifyCredentials(uid, password) {
101
+ debug('basic_auth_guard: attempting to verify credentials for uid "%s"', uid);
102
+ /**
103
+ * Attempt to find a user by the uid and raise
104
+ * error when unable to find one
105
+ */
106
+ const providerUser = await this.#userProvider.findByUid(uid);
107
+ if (!providerUser) {
108
+ this.#authenticationFailed(AuthenticationException.E_INVALID_BASIC_AUTH_CREDENTIALS());
109
+ }
110
+ /**
111
+ * Raise error when unable to verify password
112
+ */
113
+ const user = providerUser.getOriginal();
114
+ /**
115
+ * Raise error when unable to verify password
116
+ */
117
+ if (!(await providerUser.verifyPassword(password))) {
118
+ this.#authenticationFailed(AuthenticationException.E_INVALID_BASIC_AUTH_CREDENTIALS());
119
+ }
120
+ return user;
121
+ }
122
+ /**
123
+ * Authenticates the current HTTP request for basic
124
+ * auth credentials
125
+ */
126
+ async authenticate() {
127
+ /**
128
+ * Avoid re-authenticating when already authenticated
129
+ */
130
+ if (this.authenticationAttempted) {
131
+ return this.getUserOrFail();
132
+ }
133
+ /**
134
+ * Beginning authentication attempt
135
+ */
136
+ this.authenticationAttempted = true;
137
+ if (this.#emitter) {
138
+ this.#emitter.emit('basic_auth:authentication_attempted', {
139
+ ctx: this.#ctx,
140
+ guardName: this.#name,
141
+ });
142
+ }
143
+ /**
144
+ * Fetch credentials from the header
145
+ */
146
+ const credentials = auth(this.#ctx.request.request);
147
+ if (!credentials) {
148
+ this.#authenticationFailed(AuthenticationException.E_INVALID_BASIC_AUTH_CREDENTIALS());
149
+ }
150
+ debug('basic_auth_guard: authenticating user using credentials');
151
+ /**
152
+ * Verifying user credentials
153
+ */
154
+ this.user = await this.verifyCredentials(credentials.name, credentials.pass);
155
+ this.isAuthenticated = true;
156
+ debug('basic_auth_guard: marking user as authenticated');
157
+ if (this.#emitter) {
158
+ this.#emitter.emit('basic_auth:authentication_succeeded', {
159
+ ctx: this.#ctx,
160
+ guardName: this.#name,
161
+ user: this.user,
162
+ });
163
+ }
164
+ /**
165
+ * Return user
166
+ */
167
+ return this.getUserOrFail();
168
+ }
169
+ /**
170
+ * Silently attempt to authenticate the user.
171
+ *
172
+ * The method returns a boolean indicating if the authentication
173
+ * succeeded or failed.
174
+ */
175
+ async check() {
176
+ try {
177
+ await this.authenticate();
178
+ return true;
179
+ }
180
+ catch (error) {
181
+ if (error instanceof AuthenticationException) {
182
+ return false;
183
+ }
184
+ throw error;
185
+ }
186
+ }
187
+ /**
188
+ * Not support
189
+ */
190
+ async authenticateAsClient(_) {
191
+ throw new RuntimeException('Cannot authenticate as a client when using basic auth');
192
+ }
193
+ }
@@ -0,0 +1,2 @@
1
+ export { BasicAuthGuard } from './guard.js';
2
+ export { basicAuthGuard } from './define_config.js';
@@ -6,5 +6,5 @@
6
6
  * For the full copyright and license information, please view the LICENSE
7
7
  * file that was distributed with this source code.
8
8
  */
9
- import { getDirname } from '@poppinss/utils';
10
- export const stubsRoot = getDirname(import.meta.url);
9
+ export { BasicAuthGuard } from './guard.js';
10
+ export { basicAuthGuard } from './define_config.js';
@@ -0,0 +1,40 @@
1
+ import { Exception } from '@poppinss/utils';
2
+ import type { HttpContext } from '@adonisjs/core/http';
3
+ /**
4
+ * Events emitted by the basic auth guard
5
+ */
6
+ export type BasicAuthGuardEvents<User> = {
7
+ /**
8
+ * The event is emitted when the user credentials
9
+ * have been verified successfully.
10
+ */
11
+ 'basic_auth:credentials_verified': {
12
+ ctx: HttpContext;
13
+ guardName: string;
14
+ uid: string;
15
+ user: User;
16
+ };
17
+ /**
18
+ * Attempting to authenticate the user
19
+ */
20
+ 'basic_auth:authentication_attempted': {
21
+ ctx: HttpContext;
22
+ guardName: string;
23
+ };
24
+ /**
25
+ * Authentication was successful
26
+ */
27
+ 'basic_auth:authentication_succeeded': {
28
+ ctx: HttpContext;
29
+ guardName: string;
30
+ user: User;
31
+ };
32
+ /**
33
+ * Authentication failed
34
+ */
35
+ 'basic_auth:authentication_failed': {
36
+ ctx: HttpContext;
37
+ guardName: string;
38
+ error: Exception;
39
+ };
40
+ };
@@ -0,0 +1,9 @@
1
+ /*
2
+ * @adonisjs/auth
3
+ *
4
+ * (c) AdonisJS
5
+ *
6
+ * For the full copyright and license information, please view the LICENSE
7
+ * file that was distributed with this source code.
8
+ */
9
+ export {};
@@ -37,7 +37,7 @@ export function sessionGuard(config) {
37
37
  if (tokensProvider) {
38
38
  guard.withRememberMeTokens(tokensProvider);
39
39
  }
40
- return guard.withEmitter(emitter);
40
+ return guard.setEmitter(emitter);
41
41
  };
42
42
  },
43
43
  };
@@ -1,5 +1,5 @@
1
- import { Emitter } from '@adonisjs/core/events';
2
1
  import type { HttpContext } from '@adonisjs/core/http';
2
+ import type { EmitterLike } from '@adonisjs/core/types/events';
3
3
  import type { GuardContract } from '../../auth/types.js';
4
4
  import { GUARD_KNOWN_EVENTS, PROVIDER_REAL_USER } from '../../auth/symbols.js';
5
5
  import type { SessionGuardEvents, SessionGuardConfig, RememberMeProviderContract, SessionUserProviderContract } from './types.js';
@@ -10,6 +10,10 @@ import type { SessionGuardEvents, SessionGuardConfig, RememberMeProviderContract
10
10
  export declare class SessionGuard<UserProvider extends SessionUserProviderContract<unknown>> implements GuardContract<UserProvider[typeof PROVIDER_REAL_USER]> {
11
11
  #private;
12
12
  [GUARD_KNOWN_EVENTS]: SessionGuardEvents<UserProvider[typeof PROVIDER_REAL_USER]>;
13
+ /**
14
+ * Driver name of the guard
15
+ */
16
+ driverName: 'session';
13
17
  /**
14
18
  * Whether or not the authentication has been attempted
15
19
  * during the current request
@@ -67,12 +71,28 @@ export declare class SessionGuard<UserProvider extends SessionUserProviderContra
67
71
  * Register an event emitter to listen for global events for
68
72
  * authentication lifecycle.
69
73
  */
70
- withEmitter(emitter: Emitter<any>): this;
74
+ setEmitter(emitter: EmitterLike<any>): this;
71
75
  /**
72
76
  * Returns an instance of the authenticated user. Or throws
73
77
  * an exception if the request is not authenticated.
74
78
  */
75
79
  getUserOrFail(): UserProvider[typeof PROVIDER_REAL_USER];
80
+ /**
81
+ * Verifies user credentials and returns an instance of
82
+ * the user or throws "E_INVALID_CREDENTIALS" exception.
83
+ */
84
+ verifyCredentials(uid: string, password: string): Promise<UserProvider[typeof PROVIDER_REAL_USER]>;
85
+ /**
86
+ * Attempt to login a user after verifying their
87
+ * credentials.
88
+ */
89
+ attempt(uid: string, password: string, remember?: boolean): Promise<UserProvider[typeof PROVIDER_REAL_USER]>;
90
+ /**
91
+ * Attempt to login a user using the user id. The
92
+ * user will be first fetched from the db before
93
+ * marking them as logged-in
94
+ */
95
+ loginViaId(id: string | number, remember?: boolean): Promise<UserProvider[typeof PROVIDER_REAL_USER]>;
76
96
  /**
77
97
  * Login a user using the user object.
78
98
  */
@@ -89,4 +109,15 @@ export declare class SessionGuard<UserProvider extends SessionUserProviderContra
89
109
  * succeeded or failed.
90
110
  */
91
111
  check(): Promise<boolean>;
112
+ /**
113
+ * Logout user and revoke remember me token (if any)
114
+ */
115
+ logout(): Promise<void>;
116
+ /**
117
+ * Returns the session state for the user to be
118
+ * logged-in as a client
119
+ */
120
+ authenticateAsClient(user: UserProvider[typeof PROVIDER_REAL_USER]): Promise<{
121
+ session: Record<string, string | number>;
122
+ }>;
92
123
  }
@@ -9,8 +9,8 @@
9
9
  import { RuntimeException } from '@poppinss/utils';
10
10
  import debug from '../../auth/debug.js';
11
11
  import { RememberMeToken } from './token.js';
12
- import * as errors from '../../auth/errors.js';
13
12
  import { GUARD_KNOWN_EVENTS } from '../../auth/symbols.js';
13
+ import { AuthenticationException, InvalidCredentialsException } from '../../auth/errors.js';
14
14
  /**
15
15
  * Session guard uses sessions and cookies to login and authenticate
16
16
  * users.
@@ -42,6 +42,10 @@ export class SessionGuard {
42
42
  * Emitter to emit events
43
43
  */
44
44
  #emitter;
45
+ /**
46
+ * Driver name of the guard
47
+ */
48
+ driverName = 'session';
45
49
  /**
46
50
  * Whether or not the authentication has been attempted
47
51
  * during the current request
@@ -116,17 +120,33 @@ export class SessionGuard {
116
120
  return this.#ctx.session;
117
121
  }
118
122
  /**
119
- * Notifies about authenticatin failure and throws the exception
123
+ * Notifies about authentication failure and throws the exception
120
124
  */
121
125
  #authenticationFailed(error, sessionId) {
122
126
  if (this.#emitter) {
123
127
  this.#emitter.emit('session_auth:authentication_failed', {
128
+ ctx: this.#ctx,
129
+ guardName: this.#name,
124
130
  error,
125
131
  sessionId: sessionId,
126
132
  });
127
133
  }
128
134
  throw error;
129
135
  }
136
+ /**
137
+ * Notifies about login failure and throws the exception
138
+ */
139
+ #loginFailed(error, user) {
140
+ if (this.#emitter) {
141
+ this.#emitter.emit('session_auth:login_failed', {
142
+ ctx: this.#ctx,
143
+ guardName: this.#name,
144
+ error,
145
+ user,
146
+ });
147
+ }
148
+ throw error;
149
+ }
130
150
  /**
131
151
  * Register the remember me tokens provider to create
132
152
  * remember me tokens during user login.
@@ -143,7 +163,7 @@ export class SessionGuard {
143
163
  * Register an event emitter to listen for global events for
144
164
  * authentication lifecycle.
145
165
  */
146
- withEmitter(emitter) {
166
+ setEmitter(emitter) {
147
167
  this.#emitter = emitter;
148
168
  return this;
149
169
  }
@@ -153,16 +173,78 @@ export class SessionGuard {
153
173
  */
154
174
  getUserOrFail() {
155
175
  if (!this.user) {
156
- throw new errors.E_INVALID_AUTH_SESSION();
176
+ throw AuthenticationException.E_INVALID_AUTH_SESSION();
157
177
  }
158
178
  return this.user;
159
179
  }
180
+ /**
181
+ * Verifies user credentials and returns an instance of
182
+ * the user or throws "E_INVALID_CREDENTIALS" exception.
183
+ */
184
+ async verifyCredentials(uid, password) {
185
+ debug('session_guard: attempting to verify credentials for uid "%s"', uid);
186
+ /**
187
+ * Attempt to find a user by the uid and raise
188
+ * error when unable to find one
189
+ */
190
+ const providerUser = await this.#userProvider.findByUid(uid);
191
+ if (!providerUser) {
192
+ this.#loginFailed(InvalidCredentialsException.E_INVALID_CREDENTIALS(this.driverName), null);
193
+ }
194
+ /**
195
+ * Raise error when unable to verify password
196
+ */
197
+ const user = providerUser.getOriginal();
198
+ /**
199
+ * Raise error when unable to verify password
200
+ */
201
+ if (!(await providerUser.verifyPassword(password))) {
202
+ this.#loginFailed(InvalidCredentialsException.E_INVALID_CREDENTIALS(this.driverName), user);
203
+ }
204
+ /**
205
+ * Notify credentials have been verified
206
+ */
207
+ if (this.#emitter) {
208
+ this.#emitter.emit('session_auth:credentials_verified', {
209
+ ctx: this.#ctx,
210
+ guardName: this.#name,
211
+ uid,
212
+ user,
213
+ });
214
+ }
215
+ return user;
216
+ }
217
+ /**
218
+ * Attempt to login a user after verifying their
219
+ * credentials.
220
+ */
221
+ async attempt(uid, password, remember) {
222
+ const user = await this.verifyCredentials(uid, password);
223
+ return this.login(user, remember);
224
+ }
225
+ /**
226
+ * Attempt to login a user using the user id. The
227
+ * user will be first fetched from the db before
228
+ * marking them as logged-in
229
+ */
230
+ async loginViaId(id, remember) {
231
+ debug('session_guard: attempting to login user via id "%s"', id);
232
+ const providerUser = await this.#userProvider.findById(id);
233
+ if (!providerUser) {
234
+ this.#loginFailed(InvalidCredentialsException.E_INVALID_CREDENTIALS(this.driverName), null);
235
+ }
236
+ return this.login(providerUser.getOriginal(), remember);
237
+ }
160
238
  /**
161
239
  * Login a user using the user object.
162
240
  */
163
241
  async login(user, remember = false) {
164
242
  if (this.#emitter) {
165
- this.#emitter.emit('session_auth:login_attempted', { user });
243
+ this.#emitter.emit('session_auth:login_attempted', {
244
+ ctx: this.#ctx,
245
+ user,
246
+ guardName: this.#name,
247
+ });
166
248
  }
167
249
  const providerUser = await this.#userProvider.createUserForGuard(user);
168
250
  const session = this.#getSession();
@@ -209,6 +291,8 @@ export class SessionGuard {
209
291
  */
210
292
  if (this.#emitter) {
211
293
  this.#emitter.emit('session_auth:login_succeeded', {
294
+ ctx: this.#ctx,
295
+ guardName: this.#name,
212
296
  user,
213
297
  sessionId: session.sessionId,
214
298
  rememberMeToken: token,
@@ -231,6 +315,8 @@ export class SessionGuard {
231
315
  */
232
316
  if (this.#emitter) {
233
317
  this.#emitter.emit('session_auth:authentication_attempted', {
318
+ ctx: this.#ctx,
319
+ guardName: this.#name,
234
320
  sessionId: session.sessionId,
235
321
  });
236
322
  }
@@ -248,8 +334,9 @@ export class SessionGuard {
248
334
  * storage
249
335
  */
250
336
  if (!providerUser) {
251
- this.#authenticationFailed(new errors.E_INVALID_AUTH_SESSION(), session.sessionId);
337
+ this.#authenticationFailed(AuthenticationException.E_INVALID_AUTH_SESSION(), session.sessionId);
252
338
  }
339
+ debug('session_guard: marking user with id "%s" as authenticated', providerUser.getId());
253
340
  this.user = providerUser.getOriginal();
254
341
  this.isAuthenticated = true;
255
342
  this.isLoggedOut = false;
@@ -259,6 +346,8 @@ export class SessionGuard {
259
346
  */
260
347
  if (this.#emitter) {
261
348
  this.#emitter.emit('session_auth:authentication_succeeded', {
349
+ ctx: this.#ctx,
350
+ guardName: this.#name,
262
351
  sessionId: session.sessionId,
263
352
  user: this.user,
264
353
  });
@@ -280,7 +369,7 @@ export class SessionGuard {
280
369
  */
281
370
  const rememberMeCookie = this.#ctx.request.encryptedCookie(this.rememberMeKeyName);
282
371
  if (!rememberMeCookie || !this.#rememberMeTokenProvider) {
283
- this.#authenticationFailed(new errors.E_INVALID_AUTH_SESSION(), session.sessionId);
372
+ this.#authenticationFailed(AuthenticationException.E_INVALID_AUTH_SESSION(), session.sessionId);
284
373
  }
285
374
  debug('session_guard: authenticating user from remember me cookie');
286
375
  /**
@@ -289,9 +378,12 @@ export class SessionGuard {
289
378
  * is missing or invalid
290
379
  */
291
380
  const decodedToken = RememberMeToken.decode(rememberMeCookie);
381
+ if (!decodedToken) {
382
+ this.#authenticationFailed(AuthenticationException.E_INVALID_AUTH_SESSION(), session.sessionId);
383
+ }
292
384
  const token = await this.#rememberMeTokenProvider.getTokenBySeries(decodedToken.series);
293
385
  if (!token || !token.verify(decodedToken.value)) {
294
- this.#authenticationFailed(new errors.E_INVALID_AUTH_SESSION(), session.sessionId);
386
+ this.#authenticationFailed(AuthenticationException.E_INVALID_AUTH_SESSION(), session.sessionId);
295
387
  }
296
388
  debug('session_guard: found valid remember me token');
297
389
  /**
@@ -300,7 +392,7 @@ export class SessionGuard {
300
392
  */
301
393
  const providerUser = await this.#userProvider.findById(token.userId);
302
394
  if (!providerUser) {
303
- this.#authenticationFailed(new errors.E_INVALID_AUTH_SESSION(), session.sessionId);
395
+ this.#authenticationFailed(AuthenticationException.E_INVALID_AUTH_SESSION(), session.sessionId);
304
396
  }
305
397
  /**
306
398
  * Finally, login the user from the remember me token
@@ -309,6 +401,7 @@ export class SessionGuard {
309
401
  debug('session_guard: marking user with id "%s" as logged in from remember me cookie', userId);
310
402
  session.put(this.sessionKeyName, userId);
311
403
  session.regenerate();
404
+ debug('session_guard: marking user with id "%s" as authenticated', userId);
312
405
  this.user = providerUser.getOriginal();
313
406
  this.isAuthenticated = true;
314
407
  this.isLoggedOut = false;
@@ -318,6 +411,8 @@ export class SessionGuard {
318
411
  */
319
412
  if (this.#emitter) {
320
413
  this.#emitter.emit('session_auth:authentication_succeeded', {
414
+ ctx: this.#ctx,
415
+ guardName: this.#name,
321
416
  sessionId: session.sessionId,
322
417
  user: this.user,
323
418
  rememberMeToken: token,
@@ -370,11 +465,58 @@ export class SessionGuard {
370
465
  return true;
371
466
  }
372
467
  catch (error) {
373
- if (error instanceof errors.E_INVALID_AUTH_SESSION ||
374
- error instanceof errors.E_INVALID_AUTH_TOKEN) {
468
+ if (error instanceof AuthenticationException) {
375
469
  return false;
376
470
  }
377
471
  throw error;
378
472
  }
379
473
  }
474
+ /**
475
+ * Logout user and revoke remember me token (if any)
476
+ */
477
+ async logout() {
478
+ debug('session_auth: logging out');
479
+ const session = this.#getSession();
480
+ /**
481
+ * Clear client side state
482
+ */
483
+ session.forget(this.sessionKeyName);
484
+ this.#ctx.response.clearCookie(this.rememberMeKeyName);
485
+ /**
486
+ * Notify the user has been logged out
487
+ */
488
+ if (this.#emitter) {
489
+ this.#emitter.emit('session_auth:logged_out', {
490
+ ctx: this.#ctx,
491
+ guardName: this.#name,
492
+ user: this.user || null,
493
+ sessionId: session.sessionId,
494
+ });
495
+ }
496
+ const rememberMeCookie = this.#ctx.request.encryptedCookie(this.rememberMeKeyName);
497
+ if (!rememberMeCookie || !this.#rememberMeTokenProvider) {
498
+ return;
499
+ }
500
+ debug('session_auth: decoding remember me token');
501
+ const decodedToken = RememberMeToken.decode(rememberMeCookie);
502
+ if (!decodedToken) {
503
+ return;
504
+ }
505
+ debug('session_auth: deleting remember me token');
506
+ await this.#rememberMeTokenProvider.deleteTokenBySeries(decodedToken.series);
507
+ }
508
+ /**
509
+ * Returns the session state for the user to be
510
+ * logged-in as a client
511
+ */
512
+ async authenticateAsClient(user) {
513
+ const providerUser = await this.#userProvider.createUserForGuard(user);
514
+ const userId = providerUser.getId();
515
+ debug('session_guard: returning client session for user id "%s"', userId);
516
+ return {
517
+ session: {
518
+ [this.sessionKeyName]: userId,
519
+ },
520
+ };
521
+ }
380
522
  }