@adonisjs/auth 9.0.0-4 → 9.0.0-6

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.
@@ -6,31 +6,10 @@
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
- /**
10
- * Configures the user provider to use for finding
11
- * users
12
- */
13
- async function configureProvider(command) {
14
- const provider = await command.prompt.choice('Select the user provider you want to use', [
15
- {
16
- name: 'lucid',
17
- message: 'Lucid models',
18
- },
19
- {
20
- name: 'db',
21
- message: 'Database query builder',
22
- },
23
- ]);
24
- /**
25
- * Publish config file
26
- */
27
- await command.publishStub('config.stub', { provider });
28
- }
29
9
  /**
30
10
  * Configures the auth package
31
11
  */
32
12
  export async function configure(command) {
33
- await configureProvider(command);
34
13
  const codemods = await command.createCodemods();
35
14
  /**
36
15
  * Publish middleware to user application
package/build/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { configure } from './configure.js';
2
2
  export { stubsRoot } from './stubs/main.js';
3
- export * as errors from './src/auth/errors.js';
4
3
  export * as symbols from './src/auth/symbols.js';
5
4
  export { AuthManager } from './src/auth/auth_manager.js';
6
5
  export { Authenticator } from './src/auth/authenticator.js';
7
6
  export { defineConfig, providers } from './src/auth/define_config.js';
7
+ export { AuthenticationException, InvalidCredentialsException } from './src/auth/errors.js';
package/build/index.js CHANGED
@@ -8,8 +8,8 @@
8
8
  */
9
9
  export { configure } from './configure.js';
10
10
  export { stubsRoot } from './stubs/main.js';
11
- export * as errors from './src/auth/errors.js';
12
11
  export * as symbols from './src/auth/symbols.js';
13
12
  export { AuthManager } from './src/auth/auth_manager.js';
14
13
  export { Authenticator } from './src/auth/authenticator.js';
15
14
  export { defineConfig, providers } from './src/auth/define_config.js';
15
+ export { AuthenticationException, InvalidCredentialsException } from './src/auth/errors.js';
@@ -1,6 +1,7 @@
1
1
  import type { HttpContext } from '@adonisjs/core/http';
2
2
  import type { GuardFactory } from './types.js';
3
3
  import { Authenticator } from './authenticator.js';
4
+ import { AuthenticatorClient } from './authenticator_client.js';
4
5
  /**
5
6
  * Auth manager exposes the API to register and manage authentication
6
7
  * guards from the config
@@ -19,4 +20,8 @@ export declare class AuthManager<KnownGuards extends Record<string, GuardFactory
19
20
  * Create an authenticator for a given HTTP request
20
21
  */
21
22
  createAuthenticator(ctx: HttpContext): Authenticator<KnownGuards>;
23
+ /**
24
+ * Creates an instance of the authenticator client
25
+ */
26
+ createAuthenticatorClient(): AuthenticatorClient<KnownGuards>;
22
27
  }
@@ -7,6 +7,7 @@
7
7
  * file that was distributed with this source code.
8
8
  */
9
9
  import { Authenticator } from './authenticator.js';
10
+ import { AuthenticatorClient } from './authenticator_client.js';
10
11
  /**
11
12
  * Auth manager exposes the API to register and manage authentication
12
13
  * guards from the config
@@ -31,4 +32,10 @@ export class AuthManager {
31
32
  createAuthenticator(ctx) {
32
33
  return new Authenticator(ctx, this.#config);
33
34
  }
35
+ /**
36
+ * Creates an instance of the authenticator client
37
+ */
38
+ createAuthenticatorClient() {
39
+ return new AuthenticatorClient(this.#config);
40
+ }
34
41
  }
@@ -0,0 +1,23 @@
1
+ import type { GuardFactory } from './types.js';
2
+ /**
3
+ * Authenticator client is used to create guard instances for
4
+ * testing. It passes a fake HTTPContext to the guards, so
5
+ * make sure to not call server side APIs that might be
6
+ * relying on a real HTTPContext instance
7
+ */
8
+ export declare class AuthenticatorClient<KnownGuards extends Record<string, GuardFactory>> {
9
+ #private;
10
+ /**
11
+ * Name of the default guard
12
+ */
13
+ get defaultGuard(): keyof KnownGuards;
14
+ constructor(config: {
15
+ default: keyof KnownGuards;
16
+ guards: KnownGuards;
17
+ });
18
+ /**
19
+ * Returns an instance of a known guard. Guards instances are
20
+ * cached during the lifecycle of an HTTP request.
21
+ */
22
+ use<Guard extends keyof KnownGuards>(guard?: Guard): ReturnType<KnownGuards[Guard]>;
23
+ }
@@ -0,0 +1,59 @@
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 debug from './debug.js';
10
+ import { HttpContextFactory } from '@adonisjs/core/factories/http';
11
+ /**
12
+ * Authenticator client is used to create guard instances for
13
+ * testing. It passes a fake HTTPContext to the guards, so
14
+ * make sure to not call server side APIs that might be
15
+ * relying on a real HTTPContext instance
16
+ */
17
+ export class AuthenticatorClient {
18
+ /**
19
+ * Registered guards
20
+ */
21
+ #config;
22
+ /**
23
+ * Cache of guards
24
+ */
25
+ #guardsCache = {};
26
+ /**
27
+ * Name of the default guard
28
+ */
29
+ get defaultGuard() {
30
+ return this.#config.default;
31
+ }
32
+ constructor(config) {
33
+ this.#config = config;
34
+ debug('creating authenticator client. config %O', this.#config);
35
+ }
36
+ /**
37
+ * Returns an instance of a known guard. Guards instances are
38
+ * cached during the lifecycle of an HTTP request.
39
+ */
40
+ use(guard) {
41
+ const guardToUse = guard || this.#config.default;
42
+ /**
43
+ * Use cached copy if exists
44
+ */
45
+ const cachedGuard = this.#guardsCache[guardToUse];
46
+ if (cachedGuard) {
47
+ debug('using guard from cache. name: "%s"', guardToUse);
48
+ return cachedGuard;
49
+ }
50
+ const guardFactory = this.#config.guards[guardToUse];
51
+ /**
52
+ * Construct guard and cache it
53
+ */
54
+ debug('creating guard. name: "%s"', guardToUse);
55
+ const guardInstance = guardFactory(new HttpContextFactory().create());
56
+ this.#guardsCache[guardToUse] = guardInstance;
57
+ return guardInstance;
58
+ }
59
+ }
@@ -5,6 +5,8 @@ import { HttpContext } from '@adonisjs/core/http';
5
5
  * made to authenticate an HTTP request
6
6
  */
7
7
  export declare class AuthenticationException extends Exception {
8
+ static status?: number | undefined;
9
+ static code?: string | undefined;
8
10
  /**
9
11
  * Raises authentication exception when session guard
10
12
  * is unable to authenticate the request
@@ -49,6 +51,7 @@ export declare class AuthenticationException extends Exception {
49
51
  export declare class InvalidCredentialsException extends Exception {
50
52
  static message: string;
51
53
  static code: string;
54
+ static status?: number | undefined;
52
55
  static E_INVALID_CREDENTIALS(guardDriverName: string): InvalidCredentialsException;
53
56
  guardDriverName: string;
54
57
  identifier: string;
@@ -12,6 +12,8 @@ import { Exception } from '@poppinss/utils';
12
12
  * made to authenticate an HTTP request
13
13
  */
14
14
  export class AuthenticationException extends Exception {
15
+ static status = 401;
16
+ static code = 'E_UNAUTHORIZED_ACCESS';
15
17
  /**
16
18
  * Raises authentication exception when session guard
17
19
  * is unable to authenticate the request
@@ -103,6 +105,7 @@ export class AuthenticationException extends Exception {
103
105
  export class InvalidCredentialsException extends Exception {
104
106
  static message = 'Invalid credentials';
105
107
  static code = 'E_INVALID_CREDENTIALS';
108
+ static status = 400;
106
109
  static E_INVALID_CREDENTIALS(guardDriverName) {
107
110
  return new InvalidCredentialsException(InvalidCredentialsException.message, {
108
111
  guardDriverName,
@@ -0,0 +1,31 @@
1
+ import type { ApplicationService } from '@adonisjs/core/types';
2
+ import type { Authenticators, GuardContract, GuardFactory } from '../../types.js';
3
+ declare module '@japa/api-client' {
4
+ interface ApiRequest {
5
+ authData: {
6
+ guard: string;
7
+ user: unknown;
8
+ };
9
+ /**
10
+ * Login a user using the default authentication
11
+ * guard when making an API call
12
+ */
13
+ loginAs(user: {
14
+ [K in keyof Authenticators]: Authenticators[K] extends GuardFactory ? ReturnType<Authenticators[K]> extends GuardContract<infer A> ? A : never : never;
15
+ }): this;
16
+ /**
17
+ * Define the authentication guard for login
18
+ */
19
+ withGuard<K extends keyof Authenticators, Self extends ApiRequest>(this: Self, guard: K): {
20
+ /**
21
+ * Login a user using a specific auth guard
22
+ */
23
+ loginAs(user: Authenticators[K] extends GuardFactory ? ReturnType<Authenticators[K]> extends GuardContract<infer A> ? A : never : never): Self;
24
+ };
25
+ }
26
+ }
27
+ /**
28
+ * Auth API client to authenticate users when making
29
+ * HTTP requests using the Japa API client
30
+ */
31
+ export declare const authApiClient: (app: ApplicationService) => void;
@@ -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
+ /// <reference types="@adonisjs/session/plugins/api_client" />
10
+ import { ApiClient, ApiRequest } from '@japa/api-client';
11
+ /**
12
+ * Auth API client to authenticate users when making
13
+ * HTTP requests using the Japa API client
14
+ */
15
+ export const authApiClient = (app) => {
16
+ ApiRequest.macro('loginAs', function (user) {
17
+ this.authData = {
18
+ guard: '__default__',
19
+ user: user,
20
+ };
21
+ return this;
22
+ });
23
+ ApiRequest.macro('withGuard', function (guard) {
24
+ return {
25
+ loginAs: (user) => {
26
+ this.authData = {
27
+ guard,
28
+ user: user,
29
+ };
30
+ return this;
31
+ },
32
+ };
33
+ });
34
+ /**
35
+ * Hook into the request and login the user
36
+ */
37
+ ApiClient.setup(async (request) => {
38
+ const auth = await app.container.make('auth.manager');
39
+ const authData = request['authData'];
40
+ if (!authData) {
41
+ return;
42
+ }
43
+ const client = auth.createAuthenticatorClient();
44
+ const guard = authData.guard === '__default__' ? client.use() : client.use(authData.guard);
45
+ const requestData = await guard.authenticateAsClient(authData.user);
46
+ if (requestData.headers) {
47
+ request.headers(requestData.headers);
48
+ }
49
+ if (requestData.session) {
50
+ request.withSession(requestData.session);
51
+ }
52
+ if (requestData.cookies) {
53
+ request.cookies(requestData.cookies);
54
+ }
55
+ });
56
+ };
@@ -2,6 +2,14 @@ import type { HttpContext } from '@adonisjs/core/http';
2
2
  import type { ApplicationService, ConfigProvider } from '@adonisjs/core/types';
3
3
  import type { AuthManager } from './auth_manager.js';
4
4
  import type { GUARD_KNOWN_EVENTS } from './symbols.js';
5
+ /**
6
+ * The client response for authentication.
7
+ */
8
+ export interface AuthClientResponse {
9
+ headers?: Record<string, any>;
10
+ cookies?: Record<string, any>;
11
+ session?: Record<string, any>;
12
+ }
5
13
  /**
6
14
  * A set of properties a guard must implement.
7
15
  */
@@ -30,6 +38,12 @@ export interface GuardContract<User> {
30
38
  * exception
31
39
  */
32
40
  check(): Promise<boolean>;
41
+ /**
42
+ * The method is used to authenticate the user as
43
+ * client. This method should return cookies,
44
+ * headers, or session state.
45
+ */
46
+ authenticateAsClient(user: User): Promise<AuthClientResponse>;
33
47
  /**
34
48
  * Authenticates the current request and throws
35
49
  * an exception if the request is not authenticated.
@@ -64,12 +78,16 @@ export type InferAuthenticators<Config extends ConfigProvider<{
64
78
  default: unknown;
65
79
  guards: unknown;
66
80
  }>> = Awaited<ReturnType<Config['resolver']>>['guards'];
81
+ /**
82
+ * Helper to convert union to intersection
83
+ */
84
+ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
67
85
  /**
68
86
  * Infer events based upon the configure authenticators
69
87
  */
70
- export type InferAuthEvents<KnownAuthenticators extends Record<string, GuardFactory>> = {
88
+ export type InferAuthEvents<KnownAuthenticators extends Record<string, GuardFactory>> = UnionToIntersection<{
71
89
  [K in keyof KnownAuthenticators]: ReturnType<KnownAuthenticators[K]>[typeof GUARD_KNOWN_EVENTS];
72
- }[keyof KnownAuthenticators];
90
+ }[keyof KnownAuthenticators]>;
73
91
  /**
74
92
  * Auth service is a singleton instance of the AuthManager
75
93
  * configured using the config stored within the user
@@ -83,3 +101,4 @@ export interface AuthService extends AuthManager<Authenticators extends Record<s
83
101
  export type GuardConfigProvider<Guard extends GuardFactory> = {
84
102
  resolver: (name: string, app: ApplicationService) => Promise<Guard>;
85
103
  };
104
+ export {};
@@ -11,7 +11,7 @@ type DatabaseTokenRow = {
11
11
  created_at: Date;
12
12
  updated_at: Date;
13
13
  expires_at: Date | null;
14
- };
14
+ } & Record<string, any>;
15
15
  /**
16
16
  * A generic implementation to read tokens from the database
17
17
  */
@@ -113,4 +113,11 @@ export declare class SessionGuard<UserProvider extends SessionUserProviderContra
113
113
  * Logout user and revoke remember me token (if any)
114
114
  */
115
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
+ }>;
116
123
  }
@@ -491,4 +491,18 @@ export class SessionGuard {
491
491
  debug('session_auth: deleting remember me token');
492
492
  await this.#rememberMeTokenProvider.deleteTokenBySeries(decodedToken.series);
493
493
  }
494
+ /**
495
+ * Returns the session state for the user to be
496
+ * logged-in as a client
497
+ */
498
+ async authenticateAsClient(user) {
499
+ const providerUser = await this.#userProvider.createUserForGuard(user);
500
+ const userId = providerUser.getId();
501
+ debug('session_guard: returning client session for user id "%s"', userId);
502
+ return {
503
+ session: {
504
+ [this.sessionKeyName]: userId,
505
+ },
506
+ };
507
+ }
494
508
  }
@@ -1,4 +1,4 @@
1
- import { Exception } from '@poppinss/utils';
1
+ import type { Exception } from '@poppinss/utils';
2
2
  import type { RememberMeToken } from './token.js';
3
3
  import type { UserProviderContract, TokenProviderContract, DatabaseTokenProviderOptions } from '../../core/types.js';
4
4
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adonisjs/auth",
3
- "version": "9.0.0-4",
3
+ "version": "9.0.0-6",
4
4
  "description": "Official authentication provider for Adonis framework",
5
5
  "type": "module",
6
6
  "main": "build/index.js",
@@ -22,6 +22,7 @@
22
22
  ".": "./build/index.js",
23
23
  "./types": "./build/src/auth/types.js",
24
24
  "./auth_provider": "./build/providers/auth_provider.js",
25
+ "./plugins/api_client": "./build/src/auth/plugins/japa/api_client.js",
25
26
  "./services/main": "./build/services/auth.js",
26
27
  "./core/token": "./build/src/core/token.js",
27
28
  "./core/guard_user": "./build/src/core/guard_user.js",
@@ -74,6 +75,7 @@
74
75
  "@adonisjs/tsconfig": "^1.1.8",
75
76
  "@commitlint/cli": "^18.0.0",
76
77
  "@commitlint/config-conventional": "^18.0.0",
78
+ "@japa/api-client": "^2.0.0",
77
79
  "@japa/assert": "^2.0.0",
78
80
  "@japa/expect-type": "^2.0.0",
79
81
  "@japa/file-system": "^2.0.0",
@@ -132,9 +134,10 @@
132
134
  "@poppinss/utils": "^6.5.0"
133
135
  },
134
136
  "peerDependencies": {
135
- "@adonisjs/core": "^6.1.5-30",
137
+ "@adonisjs/core": "^6.1.5-31",
136
138
  "@adonisjs/lucid": "^19.0.0-3",
137
- "@adonisjs/session": "^7.0.0-13"
139
+ "@adonisjs/session": "^7.0.0-13",
140
+ "@japa/api-client": "^2.0.0"
138
141
  },
139
142
  "peerDependenciesMeta": {
140
143
  "@adonisjs/lucid": {
@@ -142,6 +145,9 @@
142
145
  },
143
146
  "@adonisjs/session": {
144
147
  "optional": true
148
+ },
149
+ "@japa/api-client": {
150
+ "optional": true
145
151
  }
146
152
  }
147
153
  }
@@ -1,42 +0,0 @@
1
- {{{
2
- exports({ to: app.configPath('auth.ts') })
3
- }}}
4
- import { defineConfig, providers } from '@adonisjs/auth'
5
- import { InferAuthEvents, Authenticators } from '@adonisjs/auth/types'
6
- {{#if provider === 'lucid'}}
7
- /**
8
- * Using the "models/user" model to find users during
9
- * login and authentication
10
- */
11
- const userProvider = providers.lucid({
12
- model: () => import('#models/user'),
13
- uids: ['email'],
14
- })
15
- {{/if}}
16
- {{#if provider === 'db'}}
17
- /**
18
- * Using Lucid query builder to directly query the database
19
- * to find users during login and authentication.
20
- */
21
- const userProvider = providers.db({
22
- table: 'users',
23
- passwordColumnName: 'password',
24
- id: 'id',
25
- uids: ['email'],
26
- })
27
- {{/if}}
28
-
29
- const authConfig = defineConfig({
30
- default: 'web',
31
- guards: {
32
- web: {} // to be configured
33
- }
34
- })
35
-
36
- export default authConfig
37
- declare module '@adonisjs/auth/types' {
38
- interface Authenticators extends InferAuthenticators<typeof authConfig> {}
39
- }
40
- declare module '@adonisjs/core/types' {
41
- interface EventsList extends InferAuthEvents<Authenticators> {}
42
- }