@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.
- package/LICENSE.md +1 -1
- package/README.md +19 -40
- package/build/configure.d.ts +5 -0
- package/build/configure.js +41 -0
- package/build/factories/database_token_factory.d.ts +36 -0
- package/build/factories/database_token_factory.js +54 -0
- package/build/factories/database_user_provider.d.ts +14 -0
- package/build/factories/database_user_provider.js +27 -0
- package/build/factories/lucid_user_provider.d.ts +28 -0
- package/build/factories/lucid_user_provider.js +68 -0
- package/build/factories/main.d.ts +4 -0
- package/build/factories/main.js +12 -0
- package/build/factories/session_guard_factory.d.ts +13 -0
- package/build/factories/session_guard_factory.js +24 -0
- package/build/index.d.ts +7 -0
- package/build/index.js +15 -0
- package/build/providers/auth_provider.d.ts +12 -0
- package/build/providers/auth_provider.js +27 -0
- package/build/services/auth.d.ts +3 -0
- package/build/services/auth.js +17 -0
- package/build/src/auth/auth_manager.d.ts +18 -0
- package/build/src/auth/auth_manager.js +28 -0
- package/build/src/auth/authenticator.d.ts +18 -0
- package/build/src/auth/authenticator.js +55 -0
- package/build/src/auth/debug.d.ts +3 -0
- package/build/{adonis-typings/container.js → src/auth/debug.js} +3 -1
- package/build/src/auth/define_config.d.ts +30 -0
- package/build/src/auth/define_config.js +54 -0
- package/build/src/auth/errors.d.ts +8 -0
- package/build/src/auth/errors.js +17 -0
- package/build/src/auth/symbols.d.ts +9 -0
- package/build/src/auth/symbols.js +17 -0
- package/build/src/auth/types.d.ts +52 -0
- package/build/{adonis-typings/context.js → src/auth/types.js} +2 -1
- package/build/src/auth/user_providers/main.d.ts +15 -0
- package/build/src/auth/user_providers/main.js +22 -0
- package/build/src/core/guard_user.d.ts +26 -0
- package/build/src/core/guard_user.js +29 -0
- package/build/src/core/token.d.ts +86 -0
- package/build/src/core/token.js +112 -0
- package/build/src/core/token_providers/database.d.ts +77 -0
- package/build/src/core/token_providers/database.js +113 -0
- package/build/src/core/types.d.ts +178 -0
- package/build/{adonis-typings/auth.js → src/core/types.js} +2 -1
- package/build/src/core/user_providers/database.d.ts +78 -0
- package/build/src/core/user_providers/database.js +117 -0
- package/build/src/core/user_providers/lucid.d.ts +61 -0
- package/build/src/core/user_providers/lucid.js +122 -0
- package/build/src/guards/session/define_config.d.ts +23 -0
- package/build/src/guards/session/define_config.js +56 -0
- package/build/src/guards/session/guard.d.ts +92 -0
- package/build/src/guards/session/guard.js +380 -0
- package/build/src/guards/session/main.d.ts +3 -0
- package/build/src/guards/session/main.js +11 -0
- package/build/src/guards/session/token.d.ts +57 -0
- package/build/src/guards/session/token.js +58 -0
- package/build/src/guards/session/token_providers/main.d.ts +33 -0
- package/build/src/guards/session/token_providers/main.js +42 -0
- package/build/src/guards/session/types.d.ts +97 -0
- package/build/{adonis-typings/events.js → src/guards/session/types.js} +2 -1
- package/build/stubs/config/auth_middleware.stub +12 -0
- package/build/stubs/config.stub +35 -0
- package/build/stubs/main.d.ts +1 -0
- package/build/{adonis-typings/tests.js → stubs/main.js} +2 -3
- package/package.json +96 -91
- package/build/adonis-typings/auth.d.ts +0 -635
- package/build/adonis-typings/container.d.ts +0 -6
- package/build/adonis-typings/context.d.ts +0 -6
- package/build/adonis-typings/events.d.ts +0 -10
- package/build/adonis-typings/index.d.ts +0 -5
- package/build/adonis-typings/index.js +0 -13
- package/build/adonis-typings/tests.d.ts +0 -23
- package/build/instructions.js +0 -338
- package/build/providers/AuthProvider.d.ts +0 -30
- package/build/providers/AuthProvider.js +0 -69
- package/build/src/Auth/index.d.ts +0 -97
- package/build/src/Auth/index.js +0 -155
- package/build/src/AuthManager/index.d.ts +0 -117
- package/build/src/AuthManager/index.js +0 -262
- package/build/src/Bindings/Tests.d.ts +0 -6
- package/build/src/Bindings/Tests.js +0 -69
- package/build/src/Clients/Oat/index.d.ts +0 -50
- package/build/src/Clients/Oat/index.js +0 -123
- package/build/src/Clients/Session/index.d.ts +0 -34
- package/build/src/Clients/Session/index.js +0 -72
- package/build/src/Exceptions/AuthenticationException.d.ts +0 -47
- package/build/src/Exceptions/AuthenticationException.js +0 -142
- package/build/src/Exceptions/InvalidCredentialsException.d.ts +0 -34
- package/build/src/Exceptions/InvalidCredentialsException.js +0 -112
- package/build/src/Guards/Base/index.d.ts +0 -75
- package/build/src/Guards/Base/index.js +0 -138
- package/build/src/Guards/BasicAuth/index.d.ts +0 -67
- package/build/src/Guards/BasicAuth/index.js +0 -181
- package/build/src/Guards/Oat/index.d.ts +0 -149
- package/build/src/Guards/Oat/index.js +0 -347
- package/build/src/Guards/Session/index.d.ts +0 -127
- package/build/src/Guards/Session/index.js +0 -338
- package/build/src/TokenProviders/Database/index.d.ts +0 -43
- package/build/src/TokenProviders/Database/index.js +0 -126
- package/build/src/TokenProviders/Redis/index.d.ts +0 -44
- package/build/src/TokenProviders/Redis/index.js +0 -129
- package/build/src/Tokens/OpaqueToken/index.d.ts +0 -46
- package/build/src/Tokens/OpaqueToken/index.js +0 -43
- package/build/src/Tokens/ProviderToken/index.d.ts +0 -23
- package/build/src/Tokens/ProviderToken/index.js +0 -27
- package/build/src/UserProviders/Database/User.d.ts +0 -28
- package/build/src/UserProviders/Database/User.js +0 -74
- package/build/src/UserProviders/Database/index.d.ts +0 -75
- package/build/src/UserProviders/Database/index.js +0 -141
- package/build/src/UserProviders/Lucid/User.d.ts +0 -28
- package/build/src/UserProviders/Lucid/User.js +0 -74
- package/build/src/UserProviders/Lucid/index.d.ts +0 -72
- package/build/src/UserProviders/Lucid/index.js +0 -146
- package/build/standalone.d.ts +0 -1
- package/build/standalone.js +0 -13
- package/build/templates/config/auth.txt +0 -34
- package/build/templates/config/partials/api-guard.txt +0 -22
- package/build/templates/config/partials/basic-guard.txt +0 -19
- package/build/templates/config/partials/tokens-provider-database.txt +0 -19
- package/build/templates/config/partials/tokens-provider-redis.txt +0 -22
- package/build/templates/config/partials/user-provider-database.txt +0 -43
- package/build/templates/config/partials/user-provider-lucid.txt +0 -45
- package/build/templates/config/partials/web-guard.txt +0 -17
- package/build/templates/contract/auth.txt +0 -55
- package/build/templates/contract/partials/api-guard.txt +0 -14
- package/build/templates/contract/partials/basic-guard.txt +0 -14
- package/build/templates/contract/partials/user-provider-database.txt +0 -16
- package/build/templates/contract/partials/user-provider-lucid.txt +0 -16
- package/build/templates/contract/partials/web-guard.txt +0 -14
- package/build/templates/middleware/Auth.txt +0 -76
- package/build/templates/middleware/SilentAuth.txt +0 -21
- package/build/templates/migrations/api_tokens.txt +0 -25
- package/build/templates/migrations/auth.txt +0 -24
- 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,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
|
+
}
|