@adonisjs/auth 9.0.0-0 → 9.0.0-10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/configure.js +5 -26
- package/build/factories/basic_auth_guard_factory.d.ts +12 -0
- package/build/factories/basic_auth_guard_factory.js +22 -0
- package/build/index.d.ts +1 -2
- package/build/index.js +1 -2
- package/build/src/auth/auth_manager.d.ts +9 -0
- package/build/src/auth/auth_manager.js +13 -0
- package/build/src/auth/authenticator.d.ts +45 -0
- package/build/src/auth/authenticator.js +74 -0
- package/build/src/auth/authenticator_client.d.ts +23 -0
- package/build/src/auth/authenticator_client.js +59 -0
- package/build/src/auth/errors.d.ts +86 -4
- package/build/src/auth/errors.js +189 -5
- package/build/src/auth/middleware/initialize_auth_middleware.d.ts +18 -0
- package/build/src/auth/middleware/initialize_auth_middleware.js +25 -0
- package/build/src/auth/plugins/japa/api_client.d.ts +32 -0
- package/build/src/auth/plugins/japa/api_client.js +63 -0
- package/build/src/auth/plugins/japa/browser_client.d.ts +25 -0
- package/build/src/auth/plugins/japa/browser_client.js +64 -0
- package/build/src/auth/types.d.ts +60 -8
- package/build/src/core/token.d.ts +4 -1
- package/build/src/core/token.js +5 -3
- package/build/src/core/token_providers/database.d.ts +1 -1
- package/build/src/guards/basic_auth/define_config.d.ts +16 -0
- package/build/src/guards/basic_auth/define_config.js +38 -0
- package/build/src/guards/basic_auth/guard.d.ts +70 -0
- package/build/src/guards/basic_auth/guard.js +193 -0
- package/build/src/guards/basic_auth/main.d.ts +2 -0
- package/build/{stubs → src/guards/basic_auth}/main.js +2 -2
- package/build/src/guards/basic_auth/types.d.ts +40 -0
- package/build/src/guards/basic_auth/types.js +9 -0
- package/build/src/guards/session/define_config.js +1 -1
- package/build/src/guards/session/guard.d.ts +33 -2
- package/build/src/guards/session/guard.js +153 -11
- package/build/src/guards/session/types.d.ts +19 -3
- package/package.json +54 -30
- package/build/stubs/config/auth_middleware.stub +0 -12
- package/build/stubs/config.stub +0 -35
- package/build/stubs/main.d.ts +0 -1
package/build/src/auth/errors.js
CHANGED
|
@@ -6,12 +6,196 @@
|
|
|
6
6
|
* For the full copyright and license information, please view the LICENSE
|
|
7
7
|
* file that was distributed with this source code.
|
|
8
8
|
*/
|
|
9
|
-
import {
|
|
9
|
+
import { Exception } from '@poppinss/utils';
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* Authentication exception is raised when an attempt is
|
|
12
|
+
* made to authenticate an HTTP request
|
|
12
13
|
*/
|
|
13
|
-
export
|
|
14
|
+
export class AuthenticationException extends Exception {
|
|
15
|
+
static status = 401;
|
|
16
|
+
static code = 'E_UNAUTHORIZED_ACCESS';
|
|
17
|
+
/**
|
|
18
|
+
* Raises authentication exception when session guard
|
|
19
|
+
* is unable to authenticate the request
|
|
20
|
+
*/
|
|
21
|
+
static E_INVALID_AUTH_SESSION() {
|
|
22
|
+
return new AuthenticationException('Invalid or expired authentication session', {
|
|
23
|
+
code: 'E_INVALID_AUTH_SESSION',
|
|
24
|
+
status: 401,
|
|
25
|
+
guardDriverName: 'session',
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Raises authentication exception when session guard
|
|
30
|
+
* is unable to authenticate the request
|
|
31
|
+
*/
|
|
32
|
+
static E_INVALID_BASIC_AUTH_CREDENTIALS() {
|
|
33
|
+
return new AuthenticationException('Invalid basic auth credentials', {
|
|
34
|
+
code: 'E_INVALID_BASIC_AUTH_CREDENTIALS',
|
|
35
|
+
status: 401,
|
|
36
|
+
guardDriverName: 'basic_auth',
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
guardDriverName;
|
|
40
|
+
redirectTo;
|
|
41
|
+
identifier = 'auth.authenticate';
|
|
42
|
+
constructor(message, options) {
|
|
43
|
+
super(message, options);
|
|
44
|
+
this.guardDriverName = options.guardDriverName;
|
|
45
|
+
this.redirectTo = options.redirectTo;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Returns the message to be sent in the HTTP response.
|
|
49
|
+
* Feel free to override this method and return a custom
|
|
50
|
+
* response.
|
|
51
|
+
*/
|
|
52
|
+
getResponseMessage(error, ctx) {
|
|
53
|
+
if ('i18n' in ctx) {
|
|
54
|
+
return ctx.i18n.t(error.identifier, {}, error.message);
|
|
55
|
+
}
|
|
56
|
+
return error.message;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A collection of authentication exception
|
|
60
|
+
* renderers to render the exception to a
|
|
61
|
+
* response.
|
|
62
|
+
*
|
|
63
|
+
* The collection is a key-value pair, where the
|
|
64
|
+
* key is the guard driver name and value is
|
|
65
|
+
* a factory function to respond to the
|
|
66
|
+
* request.
|
|
67
|
+
*/
|
|
68
|
+
renderers = {
|
|
69
|
+
session: (message, error, ctx) => {
|
|
70
|
+
switch (ctx.request.accepts(['html', 'application/vnd.api+json', 'json'])) {
|
|
71
|
+
case 'html':
|
|
72
|
+
case null:
|
|
73
|
+
ctx.session.flashExcept(['_csrf']);
|
|
74
|
+
ctx.session.flashErrors({ [error.identifier]: [message] });
|
|
75
|
+
ctx.response.redirect(error.redirectTo || '/', true);
|
|
76
|
+
break;
|
|
77
|
+
case 'json':
|
|
78
|
+
ctx.response.status(error.status).send({
|
|
79
|
+
errors: [
|
|
80
|
+
{
|
|
81
|
+
message,
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
});
|
|
85
|
+
break;
|
|
86
|
+
case 'application/vnd.api+json':
|
|
87
|
+
ctx.response.status(error.status).send({
|
|
88
|
+
errors: [
|
|
89
|
+
{
|
|
90
|
+
code: error.identifier,
|
|
91
|
+
title: message,
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
});
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
basic_auth: (message, _, ctx) => {
|
|
99
|
+
ctx.response
|
|
100
|
+
.status(this.status)
|
|
101
|
+
.header('WWW-Authenticate', `Basic realm="Authenticate", charset="UTF-8"`)
|
|
102
|
+
.send(message);
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Self handles the auth exception and converts it to an
|
|
107
|
+
* HTTP response
|
|
108
|
+
*/
|
|
109
|
+
async handle(error, ctx) {
|
|
110
|
+
const renderer = this.renderers[this.guardDriverName];
|
|
111
|
+
const message = error.getResponseMessage(error, ctx);
|
|
112
|
+
if (!renderer) {
|
|
113
|
+
return ctx.response.status(error.status).send(message);
|
|
114
|
+
}
|
|
115
|
+
return renderer(message, error, ctx);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
14
118
|
/**
|
|
15
|
-
*
|
|
119
|
+
* Invalid credentials exception is raised when unable
|
|
120
|
+
* to verify user credentials during login
|
|
16
121
|
*/
|
|
17
|
-
export
|
|
122
|
+
export class InvalidCredentialsException extends Exception {
|
|
123
|
+
static message = 'Invalid credentials';
|
|
124
|
+
static code = 'E_INVALID_CREDENTIALS';
|
|
125
|
+
static status = 400;
|
|
126
|
+
static E_INVALID_CREDENTIALS(guardDriverName) {
|
|
127
|
+
return new InvalidCredentialsException(InvalidCredentialsException.message, {
|
|
128
|
+
guardDriverName,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
guardDriverName;
|
|
132
|
+
identifier = 'auth.login';
|
|
133
|
+
constructor(message, options) {
|
|
134
|
+
super(message, options);
|
|
135
|
+
this.guardDriverName = options.guardDriverName;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Returns the message to be sent in the HTTP response.
|
|
139
|
+
* Feel free to override this method and return a custom
|
|
140
|
+
* response.
|
|
141
|
+
*/
|
|
142
|
+
getResponseMessage(error, ctx) {
|
|
143
|
+
if ('i18n' in ctx) {
|
|
144
|
+
return ctx.i18n.t(this.identifier, {}, error.message);
|
|
145
|
+
}
|
|
146
|
+
return error.message;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* A collection of authentication exception
|
|
150
|
+
* renderers to render the exception to a
|
|
151
|
+
* response.
|
|
152
|
+
*
|
|
153
|
+
* The collection is a key-value pair, where the
|
|
154
|
+
* key is the guard driver name and value is
|
|
155
|
+
* a factory function to respond to the
|
|
156
|
+
* request.
|
|
157
|
+
*/
|
|
158
|
+
renderers = {
|
|
159
|
+
session: (message, error, ctx) => {
|
|
160
|
+
switch (ctx.request.accepts(['html', 'application/vnd.api+json', 'json'])) {
|
|
161
|
+
case 'html':
|
|
162
|
+
case null:
|
|
163
|
+
ctx.session.flashExcept(['_csrf']);
|
|
164
|
+
ctx.session.flashErrors({ [this.identifier]: [message] });
|
|
165
|
+
ctx.response.redirect().withQs().back();
|
|
166
|
+
break;
|
|
167
|
+
case 'json':
|
|
168
|
+
ctx.response.status(error.status).send({
|
|
169
|
+
errors: [
|
|
170
|
+
{
|
|
171
|
+
message: message,
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
});
|
|
175
|
+
break;
|
|
176
|
+
case 'application/vnd.api+json':
|
|
177
|
+
ctx.response.status(error.status).send({
|
|
178
|
+
errors: [
|
|
179
|
+
{
|
|
180
|
+
code: this.identifier,
|
|
181
|
+
title: message,
|
|
182
|
+
},
|
|
183
|
+
],
|
|
184
|
+
});
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
/**
|
|
190
|
+
* Self handles the auth exception and converts it to an
|
|
191
|
+
* HTTP response
|
|
192
|
+
*/
|
|
193
|
+
async handle(error, ctx) {
|
|
194
|
+
const renderer = this.renderers[this.guardDriverName];
|
|
195
|
+
const message = this.getResponseMessage(error, ctx);
|
|
196
|
+
if (!renderer) {
|
|
197
|
+
return ctx.response.status(error.status).send(message);
|
|
198
|
+
}
|
|
199
|
+
return renderer(message, error, ctx);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import auth from '@adonisjs/auth/services/main';
|
|
2
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
3
|
+
import type { NextFn } from '@adonisjs/core/types/http';
|
|
4
|
+
/**
|
|
5
|
+
* The "InitializeAuthMiddleware" is used to create a request
|
|
6
|
+
* specific authenticator instance for every HTTP request.
|
|
7
|
+
*
|
|
8
|
+
* This middleware does not protect routes from unauthenticated
|
|
9
|
+
* users. Please use the "auth" middleware for that.
|
|
10
|
+
*/
|
|
11
|
+
export default class InitializeAuthMiddleware {
|
|
12
|
+
handle(ctx: HttpContext, next: NextFn): Promise<any>;
|
|
13
|
+
}
|
|
14
|
+
declare module '@adonisjs/core/http' {
|
|
15
|
+
interface HttpContext {
|
|
16
|
+
auth: ReturnType<(typeof auth)['createAuthenticator']>;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/// <reference types="@adonisjs/core/providers/edge_provider" />
|
|
2
|
+
import auth from '@adonisjs/auth/services/main';
|
|
3
|
+
/**
|
|
4
|
+
* The "InitializeAuthMiddleware" is used to create a request
|
|
5
|
+
* specific authenticator instance for every HTTP request.
|
|
6
|
+
*
|
|
7
|
+
* This middleware does not protect routes from unauthenticated
|
|
8
|
+
* users. Please use the "auth" middleware for that.
|
|
9
|
+
*/
|
|
10
|
+
export default class InitializeAuthMiddleware {
|
|
11
|
+
async handle(ctx, next) {
|
|
12
|
+
/**
|
|
13
|
+
* Initialize the authenticator for the current HTTP
|
|
14
|
+
* request
|
|
15
|
+
*/
|
|
16
|
+
ctx.auth = auth.createAuthenticator(ctx);
|
|
17
|
+
/**
|
|
18
|
+
* Sharing authenticator with templates
|
|
19
|
+
*/
|
|
20
|
+
if ('view' in ctx) {
|
|
21
|
+
ctx.view.share({ auth: ctx.auth });
|
|
22
|
+
}
|
|
23
|
+
return next();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { PluginFn } from '@japa/runner/types';
|
|
2
|
+
import type { ApplicationService } from '@adonisjs/core/types';
|
|
3
|
+
import type { Authenticators, GuardContract, GuardFactory } from '../../types.js';
|
|
4
|
+
declare module '@japa/api-client' {
|
|
5
|
+
interface ApiRequest {
|
|
6
|
+
authData: {
|
|
7
|
+
guard: string;
|
|
8
|
+
user: unknown;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Login a user using the default authentication
|
|
12
|
+
* guard when making an API call
|
|
13
|
+
*/
|
|
14
|
+
loginAs(user: {
|
|
15
|
+
[K in keyof Authenticators]: Authenticators[K] extends GuardFactory ? ReturnType<Authenticators[K]> extends GuardContract<infer A> ? A : never : never;
|
|
16
|
+
}): this;
|
|
17
|
+
/**
|
|
18
|
+
* Define the authentication guard for login
|
|
19
|
+
*/
|
|
20
|
+
withGuard<K extends keyof Authenticators, Self extends ApiRequest>(this: Self, guard: K): {
|
|
21
|
+
/**
|
|
22
|
+
* Login a user using a specific auth guard
|
|
23
|
+
*/
|
|
24
|
+
loginAs(user: Authenticators[K] extends GuardFactory ? ReturnType<Authenticators[K]> extends GuardContract<infer A> ? A : never : never): Self;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Auth API client to authenticate users when making
|
|
30
|
+
* HTTP requests using the Japa API client
|
|
31
|
+
*/
|
|
32
|
+
export declare const authApiClient: (app: ApplicationService) => PluginFn;
|
|
@@ -0,0 +1,63 @@
|
|
|
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 { ApiClient, ApiRequest } from '@japa/api-client';
|
|
10
|
+
import debug from '../../debug.js';
|
|
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
|
+
const pluginFn = function () {
|
|
17
|
+
debug('installing auth api client plugin');
|
|
18
|
+
ApiRequest.macro('loginAs', function (user) {
|
|
19
|
+
this.authData = {
|
|
20
|
+
guard: '__default__',
|
|
21
|
+
user: user,
|
|
22
|
+
};
|
|
23
|
+
return this;
|
|
24
|
+
});
|
|
25
|
+
ApiRequest.macro('withGuard', function (guard) {
|
|
26
|
+
return {
|
|
27
|
+
loginAs: (user) => {
|
|
28
|
+
this.authData = {
|
|
29
|
+
guard,
|
|
30
|
+
user: user,
|
|
31
|
+
};
|
|
32
|
+
return this;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
/**
|
|
37
|
+
* Hook into the request and login the user
|
|
38
|
+
*/
|
|
39
|
+
ApiClient.setup(async (request) => {
|
|
40
|
+
const auth = await app.container.make('auth.manager');
|
|
41
|
+
const authData = request['authData'];
|
|
42
|
+
if (!authData) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const client = auth.createAuthenticatorClient();
|
|
46
|
+
const guard = authData.guard === '__default__' ? client.use() : client.use(authData.guard);
|
|
47
|
+
const requestData = await guard.authenticateAsClient(authData.user);
|
|
48
|
+
if (requestData.headers) {
|
|
49
|
+
debug('defining headers with api client request %O', requestData.headers);
|
|
50
|
+
request.headers(requestData.headers);
|
|
51
|
+
}
|
|
52
|
+
if (requestData.session) {
|
|
53
|
+
debug('defining session with api client request %O', requestData.session);
|
|
54
|
+
request.withSession(requestData.session);
|
|
55
|
+
}
|
|
56
|
+
if (requestData.cookies) {
|
|
57
|
+
debug('defining session with api client request %O', requestData.session);
|
|
58
|
+
request.cookies(requestData.cookies);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
return pluginFn;
|
|
63
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { PluginFn } from '@japa/runner/types';
|
|
2
|
+
import type { ApplicationService } from '@adonisjs/core/types';
|
|
3
|
+
import type { Authenticators, GuardContract, GuardFactory } from '../../types.js';
|
|
4
|
+
declare module 'playwright' {
|
|
5
|
+
interface BrowserContext {
|
|
6
|
+
/**
|
|
7
|
+
* Login a user using the default authentication
|
|
8
|
+
* guard when using the browser context to
|
|
9
|
+
* make page visits
|
|
10
|
+
*/
|
|
11
|
+
loginAs(user: {
|
|
12
|
+
[K in keyof Authenticators]: Authenticators[K] extends GuardFactory ? ReturnType<Authenticators[K]> extends GuardContract<infer A> ? A : never : never;
|
|
13
|
+
}): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Define the authentication guard for login
|
|
16
|
+
*/
|
|
17
|
+
withGuard<K extends keyof Authenticators>(guard: K): {
|
|
18
|
+
/**
|
|
19
|
+
* Login a user using a specific auth guard
|
|
20
|
+
*/
|
|
21
|
+
loginAs(user: Authenticators[K] extends GuardFactory ? ReturnType<Authenticators[K]> extends GuardContract<infer A> ? A : never : never): Promise<void>;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export declare const authBrowserClient: (app: ApplicationService) => PluginFn;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adoniss/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="@japa/plugin-adonisjs" />
|
|
10
|
+
/// <reference types="@adonisjs/session/plugins/browser_client" />
|
|
11
|
+
import { RuntimeException } from '@poppinss/utils';
|
|
12
|
+
import { decoratorsCollection } from '@japa/browser-client';
|
|
13
|
+
import debug from '../../debug.js';
|
|
14
|
+
export const authBrowserClient = (app) => {
|
|
15
|
+
const pluginFn = async function () {
|
|
16
|
+
debug('installing auth browser client plugin');
|
|
17
|
+
const auth = await app.container.make('auth.manager');
|
|
18
|
+
decoratorsCollection.register({
|
|
19
|
+
context(context) {
|
|
20
|
+
context.withGuard = function (guardName) {
|
|
21
|
+
return {
|
|
22
|
+
async loginAs(user) {
|
|
23
|
+
const client = auth.createAuthenticatorClient();
|
|
24
|
+
const guard = client.use(guardName);
|
|
25
|
+
const requestData = await guard.authenticateAsClient(user);
|
|
26
|
+
if (requestData.headers) {
|
|
27
|
+
throw new RuntimeException(`Cannot use "${guard.driverName}" guard with browser client`);
|
|
28
|
+
}
|
|
29
|
+
if (requestData.cookies) {
|
|
30
|
+
debug('defining cookies with browser context %O', requestData.cookies);
|
|
31
|
+
Object.keys(requestData.cookies).forEach((cookie) => {
|
|
32
|
+
context.setCookie(cookie, requestData.cookies[cookie]);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
if (requestData.session) {
|
|
36
|
+
debug('defining session with browser context %O', requestData.session);
|
|
37
|
+
context.setSession(requestData.session);
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
context.loginAs = async function (user) {
|
|
43
|
+
const client = auth.createAuthenticatorClient();
|
|
44
|
+
const guard = client.use();
|
|
45
|
+
const requestData = await guard.authenticateAsClient(user);
|
|
46
|
+
if (requestData.headers) {
|
|
47
|
+
throw new RuntimeException(`Cannot use "${guard.driverName}" guard with browser client`);
|
|
48
|
+
}
|
|
49
|
+
if (requestData.cookies) {
|
|
50
|
+
debug('defining cookies with browser context %O', requestData.cookies);
|
|
51
|
+
Object.keys(requestData.cookies).forEach((cookie) => {
|
|
52
|
+
context.setCookie(cookie, requestData.cookies[cookie]);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
if (requestData.session) {
|
|
56
|
+
debug('defining session with browser context %O', requestData.session);
|
|
57
|
+
context.setSession(requestData.session);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
return pluginFn;
|
|
64
|
+
};
|
|
@@ -1,25 +1,63 @@
|
|
|
1
|
-
import type { Emitter } from '@adonisjs/core/events';
|
|
2
1
|
import type { HttpContext } from '@adonisjs/core/http';
|
|
3
2
|
import type { ApplicationService, ConfigProvider } from '@adonisjs/core/types';
|
|
4
3
|
import type { AuthManager } from './auth_manager.js';
|
|
5
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
|
+
}
|
|
6
13
|
/**
|
|
7
14
|
* A set of properties a guard must implement.
|
|
8
15
|
*/
|
|
9
16
|
export interface GuardContract<User> {
|
|
10
17
|
/**
|
|
11
|
-
* Reference to the user
|
|
18
|
+
* Reference to the currently authenticated user
|
|
12
19
|
*/
|
|
13
20
|
user?: User;
|
|
21
|
+
/**
|
|
22
|
+
* Returns logged-in user or throws an exception
|
|
23
|
+
*/
|
|
24
|
+
getUserOrFail(): User;
|
|
25
|
+
/**
|
|
26
|
+
* A boolean to know if the current request has
|
|
27
|
+
* been authenticated
|
|
28
|
+
*/
|
|
29
|
+
isAuthenticated: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Whether or not the authentication has been attempted
|
|
32
|
+
* during the current request
|
|
33
|
+
*/
|
|
34
|
+
authenticationAttempted: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Check if the current request has been
|
|
37
|
+
* authenticated without throwing an
|
|
38
|
+
* exception
|
|
39
|
+
*/
|
|
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>;
|
|
47
|
+
/**
|
|
48
|
+
* Authenticates the current request and throws
|
|
49
|
+
* an exception if the request is not authenticated.
|
|
50
|
+
*/
|
|
51
|
+
authenticate(): Promise<User>;
|
|
52
|
+
/**
|
|
53
|
+
* A unique name for the guard driver
|
|
54
|
+
*/
|
|
55
|
+
driverName: string;
|
|
14
56
|
/**
|
|
15
57
|
* Aymbol for infer the events emitted by a specific
|
|
16
58
|
* guard
|
|
17
59
|
*/
|
|
18
60
|
[GUARD_KNOWN_EVENTS]: unknown;
|
|
19
|
-
/**
|
|
20
|
-
* Accept an instance of the emitter to emit events
|
|
21
|
-
*/
|
|
22
|
-
withEmitter(emitter: Emitter<any>): this;
|
|
23
61
|
}
|
|
24
62
|
/**
|
|
25
63
|
* The authenticator guard factory method is called by the
|
|
@@ -36,13 +74,26 @@ export interface Authenticators {
|
|
|
36
74
|
/**
|
|
37
75
|
* Infer authenticators from the auth config
|
|
38
76
|
*/
|
|
39
|
-
export type InferAuthenticators<Config extends ConfigProvider<
|
|
77
|
+
export type InferAuthenticators<Config extends ConfigProvider<{
|
|
78
|
+
default: unknown;
|
|
79
|
+
guards: unknown;
|
|
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;
|
|
85
|
+
/**
|
|
86
|
+
* Infer events based upon the configure authenticators
|
|
87
|
+
*/
|
|
88
|
+
export type InferAuthEvents<KnownAuthenticators extends Record<string, GuardFactory>> = UnionToIntersection<{
|
|
89
|
+
[K in keyof KnownAuthenticators]: ReturnType<KnownAuthenticators[K]>[typeof GUARD_KNOWN_EVENTS];
|
|
90
|
+
}[keyof KnownAuthenticators]>;
|
|
40
91
|
/**
|
|
41
92
|
* Auth service is a singleton instance of the AuthManager
|
|
42
93
|
* configured using the config stored within the user
|
|
43
94
|
* app.
|
|
44
95
|
*/
|
|
45
|
-
export interface AuthService extends AuthManager<Authenticators extends GuardFactory ? Authenticators : never> {
|
|
96
|
+
export interface AuthService extends AuthManager<Authenticators extends Record<string, GuardFactory> ? Authenticators : never> {
|
|
46
97
|
}
|
|
47
98
|
/**
|
|
48
99
|
* Config provider for exporting guard
|
|
@@ -50,3 +101,4 @@ export interface AuthService extends AuthManager<Authenticators extends GuardFac
|
|
|
50
101
|
export type GuardConfigProvider<Guard extends GuardFactory> = {
|
|
51
102
|
resolver: (name: string, app: ApplicationService) => Promise<Guard>;
|
|
52
103
|
};
|
|
104
|
+
export {};
|
|
@@ -78,8 +78,11 @@ export declare abstract class Token implements TokenContract {
|
|
|
78
78
|
/**
|
|
79
79
|
* Decodes a publicly shared token and return the series
|
|
80
80
|
* and the token value from it.
|
|
81
|
+
*
|
|
82
|
+
* Returns null when unable to decode the token because of
|
|
83
|
+
* invalid format or encoding.
|
|
81
84
|
*/
|
|
82
|
-
static decode(value: string): {
|
|
85
|
+
static decode(value: string): null | {
|
|
83
86
|
series: string;
|
|
84
87
|
value: string;
|
|
85
88
|
};
|
package/build/src/core/token.js
CHANGED
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
import { createHash } from 'node:crypto';
|
|
10
10
|
import string from '@adonisjs/core/helpers/string';
|
|
11
11
|
import { base64, safeEqual } from '@adonisjs/core/helpers';
|
|
12
|
-
import * as errors from '../auth/errors.js';
|
|
13
12
|
/**
|
|
14
13
|
* A token represents an opaque token issued to a client
|
|
15
14
|
* to perform a specific task.
|
|
@@ -93,16 +92,19 @@ export class Token {
|
|
|
93
92
|
/**
|
|
94
93
|
* Decodes a publicly shared token and return the series
|
|
95
94
|
* and the token value from it.
|
|
95
|
+
*
|
|
96
|
+
* Returns null when unable to decode the token because of
|
|
97
|
+
* invalid format or encoding.
|
|
96
98
|
*/
|
|
97
99
|
static decode(value) {
|
|
98
100
|
const [series, ...tokenValue] = value.split('.');
|
|
99
101
|
if (!series || tokenValue.length === 0) {
|
|
100
|
-
|
|
102
|
+
return null;
|
|
101
103
|
}
|
|
102
104
|
const decodedSeries = base64.urlDecode(series);
|
|
103
105
|
const decodedValue = base64.urlDecode(tokenValue.join('.'));
|
|
104
106
|
if (!decodedSeries || !decodedValue) {
|
|
105
|
-
|
|
107
|
+
return null;
|
|
106
108
|
}
|
|
107
109
|
return {
|
|
108
110
|
series: decodedSeries,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
2
|
+
import type { ConfigProvider } from '@adonisjs/core/types';
|
|
3
|
+
import type { GuardConfigProvider } from '../../auth/types.js';
|
|
4
|
+
import type { UserProviderContract } from '../../core/types.js';
|
|
5
|
+
import { BasicAuthGuard } from './guard.js';
|
|
6
|
+
/**
|
|
7
|
+
* Helper function to configure the basic auth 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 basicAuthGuard<UserProvider extends UserProviderContract<unknown>>(config: {
|
|
15
|
+
provider: ConfigProvider<UserProvider>;
|
|
16
|
+
}): GuardConfigProvider<(ctx: HttpContext) => BasicAuthGuard<UserProvider>>;
|
|
@@ -0,0 +1,38 @@
|
|
|
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 { BasicAuthGuard } from './guard.js';
|
|
12
|
+
/**
|
|
13
|
+
* Helper function to configure the basic auth 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 basicAuthGuard(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
|
+
/**
|
|
29
|
+
* Factory function needed by Authenticator to switch
|
|
30
|
+
* between guards and perform authentication
|
|
31
|
+
*/
|
|
32
|
+
return (ctx) => {
|
|
33
|
+
const guard = new BasicAuthGuard(guardName, ctx, provider);
|
|
34
|
+
return guard.setEmitter(emitter);
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|