@adonisjs/auth 9.0.0-1 → 9.0.0-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.
@@ -32,6 +32,15 @@ async function configureProvider(command) {
32
32
  export async function configure(command) {
33
33
  await configureProvider(command);
34
34
  const codemods = await command.createCodemods();
35
+ /**
36
+ * Publish middleware to user application
37
+ */
38
+ await command.publishStub('middleware/auth_middleware.stub', {
39
+ entity: command.app.generators.createEntity('auth'),
40
+ });
41
+ await command.publishStub('middleware/guest_middleware.stub', {
42
+ entity: command.app.generators.createEntity('guest'),
43
+ });
35
44
  /**
36
45
  * Register provider
37
46
  */
@@ -49,7 +58,11 @@ export async function configure(command) {
49
58
  await codemods.registerMiddleware('named', [
50
59
  {
51
60
  name: 'auth',
52
- path: '@adonisjs/auth/auth_middleware',
61
+ path: '#middleware/auth_middleware',
62
+ },
63
+ {
64
+ name: 'guest',
65
+ path: '#middleware/guest_middleware',
53
66
  },
54
67
  ]);
55
68
  }
@@ -35,6 +35,13 @@ export declare class Authenticator<KnownGuards extends Record<string, GuardFacto
35
35
  default: keyof KnownGuards;
36
36
  guards: KnownGuards;
37
37
  });
38
+ /**
39
+ * Returns an instance of the logged-in user or throws an
40
+ * exception
41
+ */
42
+ getUserOrFail(): {
43
+ [K in keyof KnownGuards]: ReturnType<ReturnType<KnownGuards[K]>['getUserOrFail']>;
44
+ }[keyof KnownGuards];
38
45
  /**
39
46
  * Returns an instance of a known guard. Guards instances are
40
47
  * cached during the lifecycle of an HTTP request.
@@ -51,6 +58,6 @@ export declare class Authenticator<KnownGuards extends Record<string, GuardFacto
51
58
  * Otherwise, "AuthenticationException" will be raised.
52
59
  */
53
60
  authenticateUsing(guards?: (keyof KnownGuards)[], options?: {
54
- redirectTo?: string;
61
+ loginRoute?: string;
55
62
  }): Promise<boolean>;
56
63
  }
@@ -68,6 +68,13 @@ export class Authenticator {
68
68
  this.#config = config;
69
69
  debug('creating authenticator. config %O', this.#config);
70
70
  }
71
+ /**
72
+ * Returns an instance of the logged-in user or throws an
73
+ * exception
74
+ */
75
+ getUserOrFail() {
76
+ return this.use(this.#authenticatedViaGuard || this.defaultGuard).getUserOrFail();
77
+ }
71
78
  /**
72
79
  * Returns an instance of a known guard. Guards instances are
73
80
  * cached during the lifecycle of an HTTP request.
@@ -116,7 +123,7 @@ export class Authenticator {
116
123
  throw new AuthenticationException('Unauthorized access', {
117
124
  code: 'E_UNAUTHORIZED_ACCESS',
118
125
  guardDriverName: lastUsedGuardDriver,
119
- redirectTo: options?.redirectTo,
126
+ redirectTo: options?.loginRoute,
120
127
  });
121
128
  }
122
129
  }
@@ -7,6 +7,7 @@ import type { LucidAuthenticatable, LucidUserProviderOptions, DatabaseUserProvid
7
7
  */
8
8
  export type ResolvedAuthConfig<KnownGuards extends Record<string, GuardFactory | GuardConfigProvider<GuardFactory>>> = {
9
9
  default: keyof KnownGuards;
10
+ loginRoute: string;
10
11
  guards: {
11
12
  [K in keyof KnownGuards]: KnownGuards[K] extends GuardConfigProvider<infer A> ? A : KnownGuards[K];
12
13
  };
@@ -18,6 +19,7 @@ export type ResolvedAuthConfig<KnownGuards extends Record<string, GuardFactory |
18
19
  */
19
20
  export declare function defineConfig<KnownGuards extends Record<string, GuardFactory | GuardConfigProvider<GuardFactory>>>(config: {
20
21
  default: keyof KnownGuards;
22
+ loginRoute: string;
21
23
  guards: KnownGuards;
22
24
  }): ConfigProvider<ResolvedAuthConfig<KnownGuards>>;
23
25
  /**
@@ -28,6 +28,7 @@ export function defineConfig(config) {
28
28
  }
29
29
  return {
30
30
  default: config.default,
31
+ loginRoute: config.loginRoute,
31
32
  guards: guards,
32
33
  };
33
34
  });
@@ -10,6 +10,10 @@ export interface GuardContract<User> {
10
10
  * Reference to the currently authenticated user
11
11
  */
12
12
  user?: User;
13
+ /**
14
+ * Returns logged-in user or throws an exception
15
+ */
16
+ getUserOrFail(): User;
13
17
  /**
14
18
  * A boolean to know if the current request has
15
19
  * been authenticated
@@ -60,6 +64,12 @@ export type InferAuthenticators<Config extends ConfigProvider<{
60
64
  default: unknown;
61
65
  guards: unknown;
62
66
  }>> = Awaited<ReturnType<Config['resolver']>>['guards'];
67
+ /**
68
+ * Infer events based upon the configure authenticators
69
+ */
70
+ export type InferAuthEvents<KnownAuthenticators extends Record<string, GuardFactory>> = {
71
+ [K in keyof KnownAuthenticators]: ReturnType<KnownAuthenticators[K]>[typeof GUARD_KNOWN_EVENTS];
72
+ }[keyof KnownAuthenticators];
63
73
  /**
64
74
  * Auth service is a singleton instance of the AuthManager
65
75
  * configured using the config stored within the user
@@ -86,13 +86,13 @@ export declare class SessionGuard<UserProvider extends SessionUserProviderContra
86
86
  * Attempt to login a user after verifying their
87
87
  * credentials.
88
88
  */
89
- attempt(uid: string, password: string): Promise<UserProvider[typeof PROVIDER_REAL_USER]>;
89
+ attempt(uid: string, password: string, remember?: boolean): Promise<UserProvider[typeof PROVIDER_REAL_USER]>;
90
90
  /**
91
91
  * Attempt to login a user using the user id. The
92
92
  * user will be first fetched from the db before
93
93
  * marking them as logged-in
94
94
  */
95
- loginViaId(id: string | number): Promise<UserProvider[typeof PROVIDER_REAL_USER]>;
95
+ loginViaId(id: string | number, remember?: boolean): Promise<UserProvider[typeof PROVIDER_REAL_USER]>;
96
96
  /**
97
97
  * Login a user using the user object.
98
98
  */
@@ -109,4 +109,8 @@ export declare class SessionGuard<UserProvider extends SessionUserProviderContra
109
109
  * succeeded or failed.
110
110
  */
111
111
  check(): Promise<boolean>;
112
+ /**
113
+ * Logout user and revoke remember me token (if any)
114
+ */
115
+ logout(): Promise<void>;
112
116
  }
@@ -125,6 +125,7 @@ export class SessionGuard {
125
125
  #authenticationFailed(error, sessionId) {
126
126
  if (this.#emitter) {
127
127
  this.#emitter.emit('session_auth:authentication_failed', {
128
+ guardName: this.#name,
128
129
  error,
129
130
  sessionId: sessionId,
130
131
  });
@@ -137,6 +138,7 @@ export class SessionGuard {
137
138
  #loginFailed(error, user) {
138
139
  if (this.#emitter) {
139
140
  this.#emitter.emit('session_auth:login_failed', {
141
+ guardName: this.#name,
140
142
  error,
141
143
  user,
142
144
  });
@@ -202,6 +204,7 @@ export class SessionGuard {
202
204
  */
203
205
  if (this.#emitter) {
204
206
  this.#emitter.emit('session_auth:credentials_verified', {
207
+ guardName: this.#name,
205
208
  uid,
206
209
  user,
207
210
  });
@@ -212,29 +215,29 @@ export class SessionGuard {
212
215
  * Attempt to login a user after verifying their
213
216
  * credentials.
214
217
  */
215
- async attempt(uid, password) {
218
+ async attempt(uid, password, remember) {
216
219
  const user = await this.verifyCredentials(uid, password);
217
- return this.login(user);
220
+ return this.login(user, remember);
218
221
  }
219
222
  /**
220
223
  * Attempt to login a user using the user id. The
221
224
  * user will be first fetched from the db before
222
225
  * marking them as logged-in
223
226
  */
224
- async loginViaId(id) {
227
+ async loginViaId(id, remember) {
225
228
  debug('session_guard: attempting to login user via id "%s"', id);
226
229
  const providerUser = await this.#userProvider.findById(id);
227
230
  if (!providerUser) {
228
231
  this.#loginFailed(InvalidCredentialsException.E_INVALID_CREDENTIALS(this.driverName), null);
229
232
  }
230
- return this.login(providerUser.getOriginal());
233
+ return this.login(providerUser.getOriginal(), remember);
231
234
  }
232
235
  /**
233
236
  * Login a user using the user object.
234
237
  */
235
238
  async login(user, remember = false) {
236
239
  if (this.#emitter) {
237
- this.#emitter.emit('session_auth:login_attempted', { user });
240
+ this.#emitter.emit('session_auth:login_attempted', { user, guardName: this.#name });
238
241
  }
239
242
  const providerUser = await this.#userProvider.createUserForGuard(user);
240
243
  const session = this.#getSession();
@@ -281,6 +284,7 @@ export class SessionGuard {
281
284
  */
282
285
  if (this.#emitter) {
283
286
  this.#emitter.emit('session_auth:login_succeeded', {
287
+ guardName: this.#name,
284
288
  user,
285
289
  sessionId: session.sessionId,
286
290
  rememberMeToken: token,
@@ -303,6 +307,7 @@ export class SessionGuard {
303
307
  */
304
308
  if (this.#emitter) {
305
309
  this.#emitter.emit('session_auth:authentication_attempted', {
310
+ guardName: this.#name,
306
311
  sessionId: session.sessionId,
307
312
  });
308
313
  }
@@ -331,6 +336,7 @@ export class SessionGuard {
331
336
  */
332
337
  if (this.#emitter) {
333
338
  this.#emitter.emit('session_auth:authentication_succeeded', {
339
+ guardName: this.#name,
334
340
  sessionId: session.sessionId,
335
341
  user: this.user,
336
342
  });
@@ -393,6 +399,7 @@ export class SessionGuard {
393
399
  */
394
400
  if (this.#emitter) {
395
401
  this.#emitter.emit('session_auth:authentication_succeeded', {
402
+ guardName: this.#name,
396
403
  sessionId: session.sessionId,
397
404
  user: this.user,
398
405
  rememberMeToken: token,
@@ -451,4 +458,37 @@ export class SessionGuard {
451
458
  throw error;
452
459
  }
453
460
  }
461
+ /**
462
+ * Logout user and revoke remember me token (if any)
463
+ */
464
+ async logout() {
465
+ debug('session_auth: logging out');
466
+ const session = this.#getSession();
467
+ /**
468
+ * Clear client side state
469
+ */
470
+ session.forget(this.sessionKeyName);
471
+ this.#ctx.response.clearCookie(this.rememberMeKeyName);
472
+ /**
473
+ * Notify the user has been logged out
474
+ */
475
+ if (this.#emitter) {
476
+ this.#emitter.emit('session_auth:logged_out', {
477
+ guardName: this.#name,
478
+ user: this.user || null,
479
+ sessionId: session.sessionId,
480
+ });
481
+ }
482
+ const rememberMeCookie = this.#ctx.request.encryptedCookie(this.rememberMeKeyName);
483
+ if (!rememberMeCookie || !this.#rememberMeTokenProvider) {
484
+ return;
485
+ }
486
+ debug('session_auth: decoding remember me token');
487
+ const decodedToken = RememberMeToken.decode(rememberMeCookie);
488
+ if (!decodedToken) {
489
+ return;
490
+ }
491
+ debug('session_auth: deleting remember me token');
492
+ await this.#rememberMeTokenProvider.deleteTokenBySeries(decodedToken.series);
493
+ }
454
494
  }
@@ -32,6 +32,7 @@ export type SessionGuardEvents<User> = {
32
32
  * have been verified successfully.
33
33
  */
34
34
  'session_auth:credentials_verified': {
35
+ guardName: string;
35
36
  uid: string;
36
37
  user: User;
37
38
  };
@@ -40,6 +41,7 @@ export type SessionGuardEvents<User> = {
40
41
  * user.
41
42
  */
42
43
  'session_auth:login_failed': {
44
+ guardName: string;
43
45
  error: Exception;
44
46
  user: User | null;
45
47
  };
@@ -48,6 +50,7 @@ export type SessionGuardEvents<User> = {
48
50
  * a given user.
49
51
  */
50
52
  'session_auth:login_attempted': {
53
+ guardName: string;
51
54
  user: User;
52
55
  };
53
56
  /**
@@ -55,6 +58,7 @@ export type SessionGuardEvents<User> = {
55
58
  * successfully
56
59
  */
57
60
  'session_auth:login_succeeded': {
61
+ guardName: string;
58
62
  user: User;
59
63
  sessionId: string;
60
64
  rememberMeToken?: RememberMeToken;
@@ -63,12 +67,14 @@ export type SessionGuardEvents<User> = {
63
67
  * Attempting to authenticate the user
64
68
  */
65
69
  'session_auth:authentication_attempted': {
70
+ guardName: string;
66
71
  sessionId: string;
67
72
  };
68
73
  /**
69
74
  * Authentication was successful
70
75
  */
71
76
  'session_auth:authentication_succeeded': {
77
+ guardName: string;
72
78
  user: User;
73
79
  sessionId: string;
74
80
  rememberMeToken?: RememberMeToken;
@@ -77,6 +83,7 @@ export type SessionGuardEvents<User> = {
77
83
  * Authentication failed
78
84
  */
79
85
  'session_auth:authentication_failed': {
86
+ guardName: string;
80
87
  error: Exception;
81
88
  sessionId: string;
82
89
  };
@@ -85,7 +92,8 @@ export type SessionGuardEvents<User> = {
85
92
  * sucessfully
86
93
  */
87
94
  'session_auth:logged_out': {
88
- user: User;
95
+ guardName: string;
96
+ user: User | null;
89
97
  sessionId: string;
90
98
  };
91
99
  };
@@ -2,6 +2,7 @@
2
2
  exports({ to: app.configPath('auth.ts') })
3
3
  }}}
4
4
  import { defineConfig, providers } from '@adonisjs/auth'
5
+ import { InferAuthEvents, Authenticators } from '@adonisjs/auth/types'
5
6
  {{#if provider === 'lucid'}}
6
7
  /**
7
8
  * Using the "models/user" model to find users during
@@ -26,10 +27,16 @@ const userProvider = providers.db({
26
27
  {{/if}}
27
28
 
28
29
  const authConfig = defineConfig({
29
- guards: {}
30
+ default: 'web',
31
+ guards: {
32
+ web: {} // to be configured
33
+ }
30
34
  })
31
35
 
32
36
  export default authConfig
33
37
  declare module '@adonisjs/auth/types' {
34
38
  interface Authenticators extends InferAuthenticators<typeof authConfig> {}
35
39
  }
40
+ declare module '@adonisjs/core/types' {
41
+ interface EventsList extends InferAuthEvents<Authenticators> {}
42
+ }
@@ -0,0 +1,30 @@
1
+ {{#var middlewareName = generators.middlewareName(entity.name)}}
2
+ {{#var middlewareFileName = generators.middlewareFileName(entity.name)}}
3
+ {{{
4
+ exports({ to: app.middlewarePath(entity.path, middlewareFileName) })
5
+ }}}
6
+ import type { HttpContext } from '@adonisjs/core/http'
7
+ import type { NextFn } from '@adonisjs/core/types/http'
8
+ import type { Authenticators } from '@adonisjs/auth/types'
9
+
10
+ /**
11
+ * Auth middleware is used authenticate HTTP requests and deny
12
+ * access to unauthenticated users.
13
+ */
14
+ export default class {{ middlewareName }} {
15
+ /**
16
+ * The URL to redirect to, when authentication fails
17
+ */
18
+ redirectTo = '/login'
19
+
20
+ async handle(
21
+ ctx: HttpContext,
22
+ next: NextFn,
23
+ options: {
24
+ guards?: (keyof Authenticators)[]
25
+ } = {}
26
+ ) {
27
+ await ctx.auth.authenticateUsing(options.guards, { loginRoute: this.redirectTo })
28
+ return next()
29
+ }
30
+ }
@@ -0,0 +1,36 @@
1
+ {{#var middlewareName = generators.middlewareName(entity.name)}}
2
+ {{#var middlewareFileName = generators.middlewareFileName(entity.name)}}
3
+ {{{
4
+ exports({ to: app.middlewarePath(entity.path, middlewareFileName) })
5
+ }}}
6
+ import type { HttpContext } from '@adonisjs/core/http'
7
+ import type { NextFn } from '@adonisjs/core/types/http'
8
+ import type { Authenticators } from '@adonisjs/auth/types'
9
+
10
+ /**
11
+ * Guest middleware is used to deny access to routes that should
12
+ * be accessed by unauthenticated users.
13
+ *
14
+ * For example, the login page should not be accessible if the user
15
+ * is already logged-in
16
+ */
17
+ export default class {{ middlewareName }} {
18
+ /**
19
+ * The URL to redirect to when user is logged-in
20
+ */
21
+ redirectTo = '/'
22
+
23
+ async handle(
24
+ ctx: HttpContext,
25
+ next: NextFn,
26
+ options: { guards?: (keyof Authenticators)[] } = {}
27
+ ) {
28
+ for (let guard of options.guards || [ctx.auth.defaultGuard]) {
29
+ if (await ctx.auth.use(guard).check()) {
30
+ return ctx.response.redirect(this.redirectTo, true)
31
+ }
32
+ }
33
+
34
+ return next()
35
+ }
36
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adonisjs/auth",
3
- "version": "9.0.0-1",
3
+ "version": "9.0.0-4",
4
4
  "description": "Official authentication provider for Adonis framework",
5
5
  "type": "module",
6
6
  "main": "build/index.js",
@@ -30,7 +30,6 @@
30
30
  "./types/core": "./build/src/core/types.js",
31
31
  "./session": "./build/src/guards/session/main.js",
32
32
  "./initialize_auth_middleware": "./build/src/auth/middleware/initialize_auth_middleware.js",
33
- "./auth_middleware": "./build/src/auth/middleware/auth_middleware.js",
34
33
  "./types/session": "./build/src/guards/session/types.js"
35
34
  },
36
35
  "scripts": {
@@ -66,7 +65,7 @@
66
65
  },
67
66
  "devDependencies": {
68
67
  "@adonisjs/assembler": "^6.1.3-25",
69
- "@adonisjs/core": "^6.1.5-30",
68
+ "@adonisjs/core": "^6.1.5-31",
70
69
  "@adonisjs/eslint-config": "^1.1.8",
71
70
  "@adonisjs/i18n": "^2.0.0-6",
72
71
  "@adonisjs/lucid": "^19.0.0-3",
@@ -1,13 +0,0 @@
1
- import type { HttpContext } from '@adonisjs/core/http';
2
- import type { NextFn } from '@adonisjs/core/types/http';
3
- import type { Authenticators } from '@adonisjs/auth/types';
4
- /**
5
- * Options accepted by the middleware options
6
- */
7
- export type AuthMiddlewareOptions = {
8
- guards?: (keyof Authenticators)[];
9
- redirectTo?: string;
10
- };
11
- export default class AuthMiddleware {
12
- handle(ctx: HttpContext, next: NextFn, options?: AuthMiddlewareOptions): Promise<any>;
13
- }
@@ -1,6 +0,0 @@
1
- export default class AuthMiddleware {
2
- async handle(ctx, next, options = {}) {
3
- await ctx.auth.authenticateUsing(options.guards, options);
4
- return next();
5
- }
6
- }