@adonisjs/auth 8.2.3 → 9.0.0-0

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 (134) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +19 -40
  3. package/build/configure.d.ts +5 -0
  4. package/build/configure.js +41 -0
  5. package/build/factories/database_token_factory.d.ts +36 -0
  6. package/build/factories/database_token_factory.js +54 -0
  7. package/build/factories/database_user_provider.d.ts +14 -0
  8. package/build/factories/database_user_provider.js +27 -0
  9. package/build/factories/lucid_user_provider.d.ts +28 -0
  10. package/build/factories/lucid_user_provider.js +68 -0
  11. package/build/factories/main.d.ts +4 -0
  12. package/build/factories/main.js +12 -0
  13. package/build/factories/session_guard_factory.d.ts +13 -0
  14. package/build/factories/session_guard_factory.js +24 -0
  15. package/build/index.d.ts +7 -0
  16. package/build/index.js +15 -0
  17. package/build/providers/auth_provider.d.ts +12 -0
  18. package/build/providers/auth_provider.js +27 -0
  19. package/build/services/auth.d.ts +3 -0
  20. package/build/services/auth.js +17 -0
  21. package/build/src/auth/auth_manager.d.ts +18 -0
  22. package/build/src/auth/auth_manager.js +28 -0
  23. package/build/src/auth/authenticator.d.ts +18 -0
  24. package/build/src/auth/authenticator.js +55 -0
  25. package/build/src/auth/debug.d.ts +3 -0
  26. package/build/{adonis-typings/container.js → src/auth/debug.js} +3 -1
  27. package/build/src/auth/define_config.d.ts +30 -0
  28. package/build/src/auth/define_config.js +54 -0
  29. package/build/src/auth/errors.d.ts +8 -0
  30. package/build/src/auth/errors.js +17 -0
  31. package/build/src/auth/symbols.d.ts +9 -0
  32. package/build/src/auth/symbols.js +17 -0
  33. package/build/src/auth/types.d.ts +52 -0
  34. package/build/{adonis-typings/context.js → src/auth/types.js} +2 -1
  35. package/build/src/auth/user_providers/main.d.ts +15 -0
  36. package/build/src/auth/user_providers/main.js +22 -0
  37. package/build/src/core/guard_user.d.ts +26 -0
  38. package/build/src/core/guard_user.js +29 -0
  39. package/build/src/core/token.d.ts +86 -0
  40. package/build/src/core/token.js +112 -0
  41. package/build/src/core/token_providers/database.d.ts +77 -0
  42. package/build/src/core/token_providers/database.js +113 -0
  43. package/build/src/core/types.d.ts +178 -0
  44. package/build/{adonis-typings/auth.js → src/core/types.js} +2 -1
  45. package/build/src/core/user_providers/database.d.ts +78 -0
  46. package/build/src/core/user_providers/database.js +117 -0
  47. package/build/src/core/user_providers/lucid.d.ts +61 -0
  48. package/build/src/core/user_providers/lucid.js +122 -0
  49. package/build/src/guards/session/define_config.d.ts +23 -0
  50. package/build/src/guards/session/define_config.js +56 -0
  51. package/build/src/guards/session/guard.d.ts +92 -0
  52. package/build/src/guards/session/guard.js +380 -0
  53. package/build/src/guards/session/main.d.ts +3 -0
  54. package/build/src/guards/session/main.js +11 -0
  55. package/build/src/guards/session/token.d.ts +57 -0
  56. package/build/src/guards/session/token.js +58 -0
  57. package/build/src/guards/session/token_providers/main.d.ts +33 -0
  58. package/build/src/guards/session/token_providers/main.js +42 -0
  59. package/build/src/guards/session/types.d.ts +97 -0
  60. package/build/{adonis-typings/events.js → src/guards/session/types.js} +2 -1
  61. package/build/stubs/config/auth_middleware.stub +12 -0
  62. package/build/stubs/config.stub +35 -0
  63. package/build/stubs/main.d.ts +1 -0
  64. package/build/{adonis-typings/tests.js → stubs/main.js} +2 -3
  65. package/package.json +96 -91
  66. package/build/adonis-typings/auth.d.ts +0 -635
  67. package/build/adonis-typings/container.d.ts +0 -6
  68. package/build/adonis-typings/context.d.ts +0 -6
  69. package/build/adonis-typings/events.d.ts +0 -10
  70. package/build/adonis-typings/index.d.ts +0 -5
  71. package/build/adonis-typings/index.js +0 -13
  72. package/build/adonis-typings/tests.d.ts +0 -23
  73. package/build/instructions.js +0 -338
  74. package/build/providers/AuthProvider.d.ts +0 -30
  75. package/build/providers/AuthProvider.js +0 -69
  76. package/build/src/Auth/index.d.ts +0 -97
  77. package/build/src/Auth/index.js +0 -155
  78. package/build/src/AuthManager/index.d.ts +0 -117
  79. package/build/src/AuthManager/index.js +0 -262
  80. package/build/src/Bindings/Tests.d.ts +0 -6
  81. package/build/src/Bindings/Tests.js +0 -69
  82. package/build/src/Clients/Oat/index.d.ts +0 -50
  83. package/build/src/Clients/Oat/index.js +0 -123
  84. package/build/src/Clients/Session/index.d.ts +0 -34
  85. package/build/src/Clients/Session/index.js +0 -72
  86. package/build/src/Exceptions/AuthenticationException.d.ts +0 -47
  87. package/build/src/Exceptions/AuthenticationException.js +0 -142
  88. package/build/src/Exceptions/InvalidCredentialsException.d.ts +0 -34
  89. package/build/src/Exceptions/InvalidCredentialsException.js +0 -112
  90. package/build/src/Guards/Base/index.d.ts +0 -75
  91. package/build/src/Guards/Base/index.js +0 -138
  92. package/build/src/Guards/BasicAuth/index.d.ts +0 -67
  93. package/build/src/Guards/BasicAuth/index.js +0 -181
  94. package/build/src/Guards/Oat/index.d.ts +0 -149
  95. package/build/src/Guards/Oat/index.js +0 -347
  96. package/build/src/Guards/Session/index.d.ts +0 -127
  97. package/build/src/Guards/Session/index.js +0 -338
  98. package/build/src/TokenProviders/Database/index.d.ts +0 -43
  99. package/build/src/TokenProviders/Database/index.js +0 -126
  100. package/build/src/TokenProviders/Redis/index.d.ts +0 -44
  101. package/build/src/TokenProviders/Redis/index.js +0 -129
  102. package/build/src/Tokens/OpaqueToken/index.d.ts +0 -46
  103. package/build/src/Tokens/OpaqueToken/index.js +0 -43
  104. package/build/src/Tokens/ProviderToken/index.d.ts +0 -23
  105. package/build/src/Tokens/ProviderToken/index.js +0 -27
  106. package/build/src/UserProviders/Database/User.d.ts +0 -28
  107. package/build/src/UserProviders/Database/User.js +0 -74
  108. package/build/src/UserProviders/Database/index.d.ts +0 -75
  109. package/build/src/UserProviders/Database/index.js +0 -141
  110. package/build/src/UserProviders/Lucid/User.d.ts +0 -28
  111. package/build/src/UserProviders/Lucid/User.js +0 -74
  112. package/build/src/UserProviders/Lucid/index.d.ts +0 -72
  113. package/build/src/UserProviders/Lucid/index.js +0 -146
  114. package/build/standalone.d.ts +0 -1
  115. package/build/standalone.js +0 -13
  116. package/build/templates/config/auth.txt +0 -34
  117. package/build/templates/config/partials/api-guard.txt +0 -22
  118. package/build/templates/config/partials/basic-guard.txt +0 -19
  119. package/build/templates/config/partials/tokens-provider-database.txt +0 -19
  120. package/build/templates/config/partials/tokens-provider-redis.txt +0 -22
  121. package/build/templates/config/partials/user-provider-database.txt +0 -43
  122. package/build/templates/config/partials/user-provider-lucid.txt +0 -45
  123. package/build/templates/config/partials/web-guard.txt +0 -17
  124. package/build/templates/contract/auth.txt +0 -55
  125. package/build/templates/contract/partials/api-guard.txt +0 -14
  126. package/build/templates/contract/partials/basic-guard.txt +0 -14
  127. package/build/templates/contract/partials/user-provider-database.txt +0 -16
  128. package/build/templates/contract/partials/user-provider-lucid.txt +0 -16
  129. package/build/templates/contract/partials/web-guard.txt +0 -14
  130. package/build/templates/middleware/Auth.txt +0 -76
  131. package/build/templates/middleware/SilentAuth.txt +0 -21
  132. package/build/templates/migrations/api_tokens.txt +0 -25
  133. package/build/templates/migrations/auth.txt +0 -24
  134. package/build/templates/model.txt +0 -30
@@ -0,0 +1,23 @@
1
+ import type { HttpContext } from '@adonisjs/core/http';
2
+ import type { ConfigProvider } from '@adonisjs/core/types';
3
+ import { SessionGuard } from './guard.js';
4
+ import type { GuardConfigProvider } from '../../auth/types.js';
5
+ import type { SessionGuardConfig, RememberMeProviderContract, SessionUserProviderContract, DatabaseRememberMeProviderOptions } from './types.js';
6
+ /**
7
+ * Helper function to configure the session guard for
8
+ * authentication.
9
+ *
10
+ * This method returns a config builder, which internally
11
+ * returns a factory function to construct a guard
12
+ * during HTTP requests.
13
+ */
14
+ export declare function sessionGuard<UserProvider extends SessionUserProviderContract<unknown>>(config: SessionGuardConfig & {
15
+ provider: ConfigProvider<UserProvider>;
16
+ tokens?: ConfigProvider<RememberMeProviderContract>;
17
+ }): GuardConfigProvider<(ctx: HttpContext) => SessionGuard<UserProvider>>;
18
+ /**
19
+ * Tokens provider helper to store remember me tokens
20
+ */
21
+ export declare const tokensProvider: {
22
+ db: (config: DatabaseRememberMeProviderOptions) => ConfigProvider<RememberMeProviderContract>;
23
+ };
@@ -0,0 +1,56 @@
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 { configProvider } from '@adonisjs/core';
10
+ import { RuntimeException } from '@poppinss/utils';
11
+ import { SessionGuard } from './guard.js';
12
+ /**
13
+ * Helper function to configure the session guard for
14
+ * authentication.
15
+ *
16
+ * This method returns a config builder, which internally
17
+ * returns a factory function to construct a guard
18
+ * during HTTP requests.
19
+ */
20
+ export function sessionGuard(config) {
21
+ return {
22
+ async resolver(guardName, app) {
23
+ const provider = await configProvider.resolve(app, config.provider);
24
+ if (!provider) {
25
+ throw new RuntimeException(`Invalid user provider defined on "${guardName}" guard`);
26
+ }
27
+ const emitter = await app.container.make('emitter');
28
+ const tokensProvider = config.tokens
29
+ ? await configProvider.resolve(app, config.tokens)
30
+ : undefined;
31
+ /**
32
+ * Factory function needed by Authenticator to switch
33
+ * between guards and perform authentication
34
+ */
35
+ return (ctx) => {
36
+ const guard = new SessionGuard(guardName, config, ctx, provider);
37
+ if (tokensProvider) {
38
+ guard.withRememberMeTokens(tokensProvider);
39
+ }
40
+ return guard.withEmitter(emitter);
41
+ };
42
+ },
43
+ };
44
+ }
45
+ /**
46
+ * Tokens provider helper to store remember me tokens
47
+ */
48
+ export const tokensProvider = {
49
+ db(config) {
50
+ return configProvider.create(async (app) => {
51
+ const db = await app.container.make('lucid.db');
52
+ const { DatabaseRememberTokenProvider } = await import('./token_providers/main.js');
53
+ return new DatabaseRememberTokenProvider(db, config);
54
+ });
55
+ },
56
+ };
@@ -0,0 +1,92 @@
1
+ import { Emitter } from '@adonisjs/core/events';
2
+ import type { HttpContext } from '@adonisjs/core/http';
3
+ import type { GuardContract } from '../../auth/types.js';
4
+ import { GUARD_KNOWN_EVENTS, PROVIDER_REAL_USER } from '../../auth/symbols.js';
5
+ import type { SessionGuardEvents, SessionGuardConfig, RememberMeProviderContract, SessionUserProviderContract } from './types.js';
6
+ /**
7
+ * Session guard uses sessions and cookies to login and authenticate
8
+ * users.
9
+ */
10
+ export declare class SessionGuard<UserProvider extends SessionUserProviderContract<unknown>> implements GuardContract<UserProvider[typeof PROVIDER_REAL_USER]> {
11
+ #private;
12
+ [GUARD_KNOWN_EVENTS]: SessionGuardEvents<UserProvider[typeof PROVIDER_REAL_USER]>;
13
+ /**
14
+ * Whether or not the authentication has been attempted
15
+ * during the current request
16
+ */
17
+ authenticationAttempted: boolean;
18
+ /**
19
+ * Find if the user has been logged out during
20
+ * the current request
21
+ */
22
+ isLoggedOut: boolean;
23
+ /**
24
+ * A boolean to know if the current request has
25
+ * been authenticated
26
+ */
27
+ isAuthenticated: boolean;
28
+ /**
29
+ * A boolean to know if the current request is authenticated
30
+ * using the "rememember_me" token.
31
+ */
32
+ viaRemember: boolean;
33
+ /**
34
+ * Reference to an instance of the authenticated or logged-in
35
+ * user. The value only exists after calling one of the
36
+ * following methods.
37
+ *
38
+ * - login
39
+ * - loginViaId
40
+ * - attempt
41
+ * - authenticate
42
+ *
43
+ * You can use the "getUserOrFail" method to throw an exception if
44
+ * the request is not authenticated.
45
+ */
46
+ user?: UserProvider[typeof PROVIDER_REAL_USER];
47
+ /**
48
+ * The key used to store the logged-in user id inside
49
+ * session
50
+ */
51
+ get sessionKeyName(): string;
52
+ /**
53
+ * The key used to store the remember me token cookie
54
+ */
55
+ get rememberMeKeyName(): string;
56
+ constructor(name: string, config: SessionGuardConfig, ctx: HttpContext, userProvider: UserProvider);
57
+ /**
58
+ * Register the remember me tokens provider to create
59
+ * remember me tokens during user login.
60
+ *
61
+ * Note: This method only registers the remember me tokens provider
62
+ * and does not enable them. You must pass "rememberMe = true" during
63
+ * the "login" method call.
64
+ */
65
+ withRememberMeTokens(tokensProvider: RememberMeProviderContract): this;
66
+ /**
67
+ * Register an event emitter to listen for global events for
68
+ * authentication lifecycle.
69
+ */
70
+ withEmitter(emitter: Emitter<any>): this;
71
+ /**
72
+ * Returns an instance of the authenticated user. Or throws
73
+ * an exception if the request is not authenticated.
74
+ */
75
+ getUserOrFail(): UserProvider[typeof PROVIDER_REAL_USER];
76
+ /**
77
+ * Login a user using the user object.
78
+ */
79
+ login(user: UserProvider[typeof PROVIDER_REAL_USER], remember?: boolean): Promise<UserProvider[typeof PROVIDER_REAL_USER]>;
80
+ /**
81
+ * Authenticates the HTTP request to ensure the
82
+ * user is logged-in
83
+ */
84
+ authenticate(): Promise<UserProvider[typeof PROVIDER_REAL_USER]>;
85
+ /**
86
+ * Silently attempt to authenticate the user.
87
+ *
88
+ * The method returns a boolean indicating if the authentication
89
+ * succeeded or failed.
90
+ */
91
+ check(): Promise<boolean>;
92
+ }
@@ -0,0 +1,380 @@
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 { RuntimeException } from '@poppinss/utils';
10
+ import debug from '../../auth/debug.js';
11
+ import { RememberMeToken } from './token.js';
12
+ import * as errors from '../../auth/errors.js';
13
+ import { GUARD_KNOWN_EVENTS } from '../../auth/symbols.js';
14
+ /**
15
+ * Session guard uses sessions and cookies to login and authenticate
16
+ * users.
17
+ */
18
+ export class SessionGuard {
19
+ /**
20
+ * A unique name for the guard. It is used for prefixing
21
+ * session data and remember me cookies
22
+ */
23
+ #name;
24
+ /**
25
+ * Reference to the current HTTP context
26
+ */
27
+ #ctx;
28
+ /**
29
+ * Configuration
30
+ */
31
+ #config;
32
+ /**
33
+ * Provider to lookup user details
34
+ */
35
+ #userProvider;
36
+ /**
37
+ * The remember me tokens provider to use to persist
38
+ * remember me tokens
39
+ */
40
+ #rememberMeTokenProvider;
41
+ /**
42
+ * Emitter to emit events
43
+ */
44
+ #emitter;
45
+ /**
46
+ * Whether or not the authentication has been attempted
47
+ * during the current request
48
+ */
49
+ authenticationAttempted = false;
50
+ /**
51
+ * Find if the user has been logged out during
52
+ * the current request
53
+ */
54
+ isLoggedOut = false;
55
+ /**
56
+ * A boolean to know if the current request has
57
+ * been authenticated
58
+ */
59
+ isAuthenticated = false;
60
+ /**
61
+ * A boolean to know if the current request is authenticated
62
+ * using the "rememember_me" token.
63
+ */
64
+ viaRemember = false;
65
+ /**
66
+ * Reference to an instance of the authenticated or logged-in
67
+ * user. The value only exists after calling one of the
68
+ * following methods.
69
+ *
70
+ * - login
71
+ * - loginViaId
72
+ * - attempt
73
+ * - authenticate
74
+ *
75
+ * You can use the "getUserOrFail" method to throw an exception if
76
+ * the request is not authenticated.
77
+ */
78
+ user;
79
+ /**
80
+ * The key used to store the logged-in user id inside
81
+ * session
82
+ */
83
+ get sessionKeyName() {
84
+ return `auth_${this.#name}`;
85
+ }
86
+ /**
87
+ * The key used to store the remember me token cookie
88
+ */
89
+ get rememberMeKeyName() {
90
+ return `remember_${this.#name}`;
91
+ }
92
+ constructor(name, config, ctx, userProvider) {
93
+ this.#name = name;
94
+ this.#ctx = ctx;
95
+ this.#config = config;
96
+ this.#userProvider = userProvider;
97
+ }
98
+ /**
99
+ * Returns an instance of the tokens provider, ensuring
100
+ * it has been configured
101
+ */
102
+ #getTokenProvider() {
103
+ if (!this.#rememberMeTokenProvider) {
104
+ throw new RuntimeException('Cannot use "rememberMe" feature. Please configure the tokens provider inside config/auth file');
105
+ }
106
+ return this.#rememberMeTokenProvider;
107
+ }
108
+ /**
109
+ * Returns the session instance for the given request,
110
+ * ensuring the property exists
111
+ */
112
+ #getSession() {
113
+ if (!('session' in this.#ctx)) {
114
+ throw new RuntimeException('Cannot login user. Make sure you have installed the "@adonisjs/session" package and configured its middleware');
115
+ }
116
+ return this.#ctx.session;
117
+ }
118
+ /**
119
+ * Notifies about authenticatin failure and throws the exception
120
+ */
121
+ #authenticationFailed(error, sessionId) {
122
+ if (this.#emitter) {
123
+ this.#emitter.emit('session_auth:authentication_failed', {
124
+ error,
125
+ sessionId: sessionId,
126
+ });
127
+ }
128
+ throw error;
129
+ }
130
+ /**
131
+ * Register the remember me tokens provider to create
132
+ * remember me tokens during user login.
133
+ *
134
+ * Note: This method only registers the remember me tokens provider
135
+ * and does not enable them. You must pass "rememberMe = true" during
136
+ * the "login" method call.
137
+ */
138
+ withRememberMeTokens(tokensProvider) {
139
+ this.#rememberMeTokenProvider = tokensProvider;
140
+ return this;
141
+ }
142
+ /**
143
+ * Register an event emitter to listen for global events for
144
+ * authentication lifecycle.
145
+ */
146
+ withEmitter(emitter) {
147
+ this.#emitter = emitter;
148
+ return this;
149
+ }
150
+ /**
151
+ * Returns an instance of the authenticated user. Or throws
152
+ * an exception if the request is not authenticated.
153
+ */
154
+ getUserOrFail() {
155
+ if (!this.user) {
156
+ throw new errors.E_INVALID_AUTH_SESSION();
157
+ }
158
+ return this.user;
159
+ }
160
+ /**
161
+ * Login a user using the user object.
162
+ */
163
+ async login(user, remember = false) {
164
+ if (this.#emitter) {
165
+ this.#emitter.emit('session_auth:login_attempted', { user });
166
+ }
167
+ const providerUser = await this.#userProvider.createUserForGuard(user);
168
+ const session = this.#getSession();
169
+ /**
170
+ * Create session and recycle the session id
171
+ */
172
+ const userId = providerUser.getId();
173
+ debug('session_guard: marking user with id "%s" as logged-in', userId);
174
+ session.put(this.sessionKeyName, userId);
175
+ session.regenerate();
176
+ /**
177
+ * Manage remember me cookie
178
+ */
179
+ let token;
180
+ if (remember) {
181
+ const tokenProvider = this.#getTokenProvider();
182
+ /**
183
+ * Create a token
184
+ */
185
+ token = RememberMeToken.create(providerUser.getId(), this.#config.rememberMeTokenAge || '2years');
186
+ /**
187
+ * Persist remember me token inside the database
188
+ */
189
+ await tokenProvider.createToken(token);
190
+ /**
191
+ * Drop token value inside the cookie
192
+ */
193
+ debug('session_guard: creating remember me cookie');
194
+ this.#ctx.response.encryptedCookie(this.rememberMeKeyName, token.value, {
195
+ maxAge: this.#config.rememberMeTokenAge,
196
+ httpOnly: true,
197
+ });
198
+ }
199
+ else {
200
+ this.#ctx.response.clearCookie(this.rememberMeKeyName);
201
+ }
202
+ /**
203
+ * Toggle properties to mark user as logged-in
204
+ */
205
+ this.user = user;
206
+ this.isLoggedOut = false;
207
+ /**
208
+ * Notify the login is successful
209
+ */
210
+ if (this.#emitter) {
211
+ this.#emitter.emit('session_auth:login_succeeded', {
212
+ user,
213
+ sessionId: session.sessionId,
214
+ rememberMeToken: token,
215
+ });
216
+ }
217
+ return user;
218
+ }
219
+ /**
220
+ * Authenticates the HTTP request to ensure the
221
+ * user is logged-in
222
+ */
223
+ async authenticate() {
224
+ if (this.authenticationAttempted) {
225
+ return this.getUserOrFail();
226
+ }
227
+ this.authenticationAttempted = true;
228
+ const session = this.#getSession();
229
+ /**
230
+ * Notify we are starting authentication process
231
+ */
232
+ if (this.#emitter) {
233
+ this.#emitter.emit('session_auth:authentication_attempted', {
234
+ sessionId: session.sessionId,
235
+ });
236
+ }
237
+ /**
238
+ * Check if there is a user id inside the session store.
239
+ * If yes, fetch the user from the persistent storage
240
+ * and mark them as logged-in
241
+ */
242
+ const loggedInUserId = session.get(this.sessionKeyName);
243
+ if (loggedInUserId) {
244
+ debug('session_guard: authenticating user from session');
245
+ const providerUser = await this.#userProvider.findById(loggedInUserId);
246
+ /**
247
+ * Throw error when user is not found inside the persistent
248
+ * storage
249
+ */
250
+ if (!providerUser) {
251
+ this.#authenticationFailed(new errors.E_INVALID_AUTH_SESSION(), session.sessionId);
252
+ }
253
+ this.user = providerUser.getOriginal();
254
+ this.isAuthenticated = true;
255
+ this.isLoggedOut = false;
256
+ this.viaRemember = false;
257
+ /**
258
+ * Authentication was successful
259
+ */
260
+ if (this.#emitter) {
261
+ this.#emitter.emit('session_auth:authentication_succeeded', {
262
+ sessionId: session.sessionId,
263
+ user: this.user,
264
+ });
265
+ }
266
+ return this.user;
267
+ }
268
+ /**
269
+ * Otherwise check for remember me cookie and attempt
270
+ * to login user via that.
271
+ *
272
+ * Also, if the remember me token provider is not registered,
273
+ * we will silently ignore the remember me cookie and
274
+ * throw invalid session exception
275
+ *
276
+ * This is because, sometimes an app might use the remember me
277
+ * tokens initially and then back out and stop using them. In
278
+ * that case, we should not fail authentication attempts, just
279
+ * ignore the remember me cookie.
280
+ */
281
+ const rememberMeCookie = this.#ctx.request.encryptedCookie(this.rememberMeKeyName);
282
+ if (!rememberMeCookie || !this.#rememberMeTokenProvider) {
283
+ this.#authenticationFailed(new errors.E_INVALID_AUTH_SESSION(), session.sessionId);
284
+ }
285
+ debug('session_guard: authenticating user from remember me cookie');
286
+ /**
287
+ * Decode remember me cookie and check for its existence inside
288
+ * the database. Throw invalid session exception when token
289
+ * is missing or invalid
290
+ */
291
+ const decodedToken = RememberMeToken.decode(rememberMeCookie);
292
+ const token = await this.#rememberMeTokenProvider.getTokenBySeries(decodedToken.series);
293
+ if (!token || !token.verify(decodedToken.value)) {
294
+ this.#authenticationFailed(new errors.E_INVALID_AUTH_SESSION(), session.sessionId);
295
+ }
296
+ debug('session_guard: found valid remember me token');
297
+ /**
298
+ * Find user for whom the token was created. Throw invalid
299
+ * session exception when the user is missing
300
+ */
301
+ const providerUser = await this.#userProvider.findById(token.userId);
302
+ if (!providerUser) {
303
+ this.#authenticationFailed(new errors.E_INVALID_AUTH_SESSION(), session.sessionId);
304
+ }
305
+ /**
306
+ * Finally, login the user from the remember me token
307
+ */
308
+ const userId = providerUser.getId();
309
+ debug('session_guard: marking user with id "%s" as logged in from remember me cookie', userId);
310
+ session.put(this.sessionKeyName, userId);
311
+ session.regenerate();
312
+ this.user = providerUser.getOriginal();
313
+ this.isAuthenticated = true;
314
+ this.isLoggedOut = false;
315
+ this.viaRemember = true;
316
+ /**
317
+ * Authentication was successful via remember me token
318
+ */
319
+ if (this.#emitter) {
320
+ this.#emitter.emit('session_auth:authentication_succeeded', {
321
+ sessionId: session.sessionId,
322
+ user: this.user,
323
+ rememberMeToken: token,
324
+ });
325
+ }
326
+ /**
327
+ * ----------------------------------------------------------------
328
+ * User is logged in now. From here on we are refreshing the
329
+ * remember me token.
330
+ * ----------------------------------------------------------------
331
+ *
332
+ * Here we refresh the token value inside the db when the
333
+ * current remember_me token is older than 1 minute.
334
+ *
335
+ * Otherwise, we re-use the same token. This is avoid race-conditions
336
+ * when parallel requests uses the remember_me token to authenticate
337
+ * the user.
338
+ *
339
+ * Finally, we will update remember_me cookie lifespan in both the cases.
340
+ * Be it updated the token inside databse, or not.
341
+ */
342
+ const currentTime = new Date();
343
+ const updatedAtWithBuffer = new Date(token.updatedAt);
344
+ updatedAtWithBuffer.setSeconds(updatedAtWithBuffer.getSeconds() + 60);
345
+ if (updatedAtWithBuffer < currentTime) {
346
+ const newToken = RememberMeToken.create(token.userId, this.#config.rememberMeTokenAge || '2years');
347
+ await this.#rememberMeTokenProvider.updateTokenBySeries(token.series, newToken.hash, newToken.expiresAt);
348
+ this.#ctx.response.encryptedCookie(this.rememberMeKeyName, newToken.value, {
349
+ maxAge: this.#config.rememberMeTokenAge,
350
+ httpOnly: true,
351
+ });
352
+ }
353
+ else {
354
+ this.#ctx.response.encryptedCookie(this.rememberMeKeyName, rememberMeCookie, {
355
+ maxAge: this.#config.rememberMeTokenAge,
356
+ httpOnly: true,
357
+ });
358
+ }
359
+ return this.user;
360
+ }
361
+ /**
362
+ * Silently attempt to authenticate the user.
363
+ *
364
+ * The method returns a boolean indicating if the authentication
365
+ * succeeded or failed.
366
+ */
367
+ async check() {
368
+ try {
369
+ await this.authenticate();
370
+ return true;
371
+ }
372
+ catch (error) {
373
+ if (error instanceof errors.E_INVALID_AUTH_SESSION ||
374
+ error instanceof errors.E_INVALID_AUTH_TOKEN) {
375
+ return false;
376
+ }
377
+ throw error;
378
+ }
379
+ }
380
+ }
@@ -0,0 +1,3 @@
1
+ export { SessionGuard } from './guard.js';
2
+ export { RememberMeToken } from './token.js';
3
+ export { sessionGuard, tokensProvider } from './define_config.js';
@@ -0,0 +1,11 @@
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 { SessionGuard } from './guard.js';
10
+ export { RememberMeToken } from './token.js';
11
+ export { sessionGuard, tokensProvider } from './define_config.js';
@@ -0,0 +1,57 @@
1
+ import { Token } from '../../core/token.js';
2
+ /**
3
+ * Remember me token represents a remember me token created
4
+ * for a peristed login flow.
5
+ */
6
+ export declare class RememberMeToken extends Token {
7
+ /**
8
+ * Reference to the user id for whom the token
9
+ * is generated
10
+ */
11
+ userId: string | number;
12
+ /**
13
+ * Series is a random number stored inside the database as it is
14
+ */
15
+ series: string;
16
+ /**
17
+ * Value is a random number only available at the time of issuing
18
+ * the token. Afterwards, the value is undefined.
19
+ */
20
+ value: string | undefined;
21
+ /**
22
+ * Hash reference to the token hash
23
+ */
24
+ hash: string;
25
+ /**
26
+ * Static name for the token to uniquely identify a
27
+ * bucket of tokens
28
+ */
29
+ readonly type: 'remember_me_token';
30
+ /**
31
+ * Timestamp at which the token will expire
32
+ */
33
+ expiresAt: Date;
34
+ constructor(
35
+ /**
36
+ * Reference to the user id for whom the token
37
+ * is generated
38
+ */
39
+ userId: string | number,
40
+ /**
41
+ * Series is a random number stored inside the database as it is
42
+ */
43
+ series: string,
44
+ /**
45
+ * Value is a random number only available at the time of issuing
46
+ * the token. Afterwards, the value is undefined.
47
+ */
48
+ value: string | undefined,
49
+ /**
50
+ * Hash reference to the token hash
51
+ */
52
+ hash: string);
53
+ /**
54
+ * Create remember me token instance for a user
55
+ */
56
+ static create(userId: string | number, expiry: string | number, size?: number): RememberMeToken;
57
+ }
@@ -0,0 +1,58 @@
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 { Token } from '../../core/token.js';
10
+ /**
11
+ * Remember me token represents a remember me token created
12
+ * for a peristed login flow.
13
+ */
14
+ export class RememberMeToken extends Token {
15
+ userId;
16
+ series;
17
+ value;
18
+ hash;
19
+ /**
20
+ * Static name for the token to uniquely identify a
21
+ * bucket of tokens
22
+ */
23
+ type = 'remember_me_token';
24
+ constructor(
25
+ /**
26
+ * Reference to the user id for whom the token
27
+ * is generated
28
+ */
29
+ userId,
30
+ /**
31
+ * Series is a random number stored inside the database as it is
32
+ */
33
+ series,
34
+ /**
35
+ * Value is a random number only available at the time of issuing
36
+ * the token. Afterwards, the value is undefined.
37
+ */
38
+ value,
39
+ /**
40
+ * Hash reference to the token hash
41
+ */
42
+ hash) {
43
+ super(series, value, hash);
44
+ this.userId = userId;
45
+ this.series = series;
46
+ this.value = value;
47
+ this.hash = hash;
48
+ }
49
+ /**
50
+ * Create remember me token instance for a user
51
+ */
52
+ static create(userId, expiry, size) {
53
+ const { series, value, hash } = this.seed(size);
54
+ const token = new RememberMeToken(userId, series, value, hash);
55
+ token.setExpiry(expiry);
56
+ return token;
57
+ }
58
+ }