@antelopejs/interface-auth 0.0.7 → 0.2.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/README.md +20 -14
- package/dist/antelope.test.js +1 -5
- package/dist/antelope.test.js.map +1 -1
- package/dist/index.d.ts +79 -28
- package/dist/index.js +50 -76
- package/dist/index.js.map +1 -1
- package/dist/tests/class-decorator.test.d.ts +1 -0
- package/dist/tests/class-decorator.test.js +20 -0
- package/dist/tests/class-decorator.test.js.map +1 -0
- package/dist/tests/index.test.js +32 -57
- package/dist/tests/index.test.js.map +1 -1
- package/dist/tests/local-build.test.d.ts +1 -0
- package/dist/tests/local-build.test.js +147 -0
- package/dist/tests/local-build.test.js.map +1 -0
- package/docs/1.introduction.md +51 -11
- package/docs/2.authentication.md +51 -39
- package/docs/3.token-handling.md +60 -38
- package/docs/4.parameter-decoration.md +45 -29
- package/docs/assets/authentication-pipeline.svg +21 -0
- package/package.json +25 -6
- package/skills/auth-interface/SKILL.md +8 -2
- package/skills/auth-interface/cases.json +73 -0
package/README.md
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@antelopejs/interface-auth`
|
|
2
2
|
|
|
3
3
|
<div align="center">
|
|
4
|
-
<a href="https://www.npmjs.com/package/@antelopejs/interface-auth"><img alt="npm" src="https://img.shields.io/npm/v/@antelopejs/interface-auth?style=for-the-badge&labelColor=000000&color=000000"></a>
|
|
5
|
-
<a href="./LICENSE"><img alt="License" src="https://img.shields.io/npm/l/@antelopejs/interface-auth?style=for-the-badge&labelColor=000000&color=000000"></a>
|
|
6
|
-
<a href="https://discord.gg/
|
|
7
|
-
<a href="https://interfaces.antelopejs.com/docs/auth"><img alt="Docs" src="https://img.shields.io/badge/Docs-18181B?style=for-the-badge&color=000000"></a>
|
|
4
|
+
<a href="https://www.npmjs.com/package/@antelopejs/interface-auth"><img data-illustration alt="npm" src="https://img.shields.io/npm/v/@antelopejs/interface-auth?style=for-the-badge&labelColor=000000&color=000000"></a>
|
|
5
|
+
<a href="./LICENSE"><img data-illustration alt="License" src="https://img.shields.io/npm/l/@antelopejs/interface-auth?style=for-the-badge&labelColor=000000&color=000000"></a>
|
|
6
|
+
<a href="https://discord.gg/g4pFt6eXqu"><img data-illustration alt="Discord" src="https://img.shields.io/badge/Discord-18181B?logo=discord&style=for-the-badge&color=000000"></a>
|
|
7
|
+
<a href="https://interfaces.antelopejs.com/docs/auth"><img data-illustration alt="Docs" src="https://img.shields.io/badge/Docs-18181B?style=for-the-badge&color=000000"></a>
|
|
8
8
|
</div>
|
|
9
9
|
|
|
10
10
|
The AntelopeJS contract for token authentication: sign and verify tokens, and inject the verified payload into API handlers with a decorator.
|
|
11
11
|
|
|
12
|
+
Part of [AntelopeJS](https://github.com/AntelopeJS/antelopejs), the TypeScript framework where modules depend on contracts and the application chooses the provider. Built by the team behind [AntelopeJS DMS](https://github.com/AntelopeJS/dms).
|
|
13
|
+
|
|
12
14
|
## What it offers
|
|
13
15
|
|
|
14
16
|
- `SignRaw` and `ValidateRaw` sign a payload into a token and verify a token back into its payload.
|
|
15
17
|
- `SignServerResponse` signs a payload and attaches the token to a response as a cookie.
|
|
16
|
-
- `@Authentication()` reads the token from the `x-antelopejs-auth` header,
|
|
17
|
-
- `CreateAuthDecorator` builds your own decorator with a custom source, verifier and validator.
|
|
18
|
+
- `@Authentication()` reads the token from the `x-antelopejs-auth` header, or from the `ANTELOPEJS_AUTH` cookie when the header is absent. It verifies the token and injects the payload into a handler parameter.
|
|
19
|
+
- `CreateAuthDecorator` builds your own decorator with a custom source, verifier, and validator.
|
|
18
20
|
|
|
19
21
|
## Implementations
|
|
20
22
|
|
|
@@ -59,7 +61,9 @@ export class SessionController extends Controller("/session") {
|
|
|
59
61
|
}
|
|
60
62
|
```
|
|
61
63
|
|
|
62
|
-
A request to `GET /session/me` without a valid token fails before the handler runs. Send the token unchanged in `x-antelopejs-auth`, without a `Bearer ` prefix. The login method only
|
|
64
|
+
A request to `GET /session/me` without a valid token fails before the handler runs. Send the token unchanged in `x-antelopejs-auth`, without a `Bearer ` prefix. The `login` method only shows signing. In a real application, check the credentials before you issue a token.
|
|
65
|
+
|
|
66
|
+
The `Session` annotation describes the payload the application expects. It does not check it, so `session.id` is whatever the verified token carries. Add a [shape-checking verifier](./docs/2.authentication.md#create-a-custom-verifier) before you rely on claims from tokens whose format nothing enforces.
|
|
63
67
|
|
|
64
68
|
## Documentation
|
|
65
69
|
|
|
@@ -70,14 +74,16 @@ A request to `GET /session/me` without a valid token fails before the handler ru
|
|
|
70
74
|
|
|
71
75
|
## Compatibility
|
|
72
76
|
|
|
73
|
-
|
|
77
|
+
The module declares these peer dependencies:
|
|
78
|
+
|
|
79
|
+
<!-- antelopejs-docs-compat:start -->
|
|
74
80
|
|
|
75
|
-
|
|
81
|
+
| Package | Supported | Tested with |
|
|
82
|
+
| ---------------------------- | ----------------- | ----------- |
|
|
83
|
+
| `@antelopejs/interface-api` | `>=0.0.15 <1.0.0` | `0.2.0` |
|
|
84
|
+
| `@antelopejs/interface-core` | `>=0.2.4 <1.0.0` | `0.4.0` |
|
|
76
85
|
|
|
77
|
-
|
|
78
|
-
| ---------------------------- | ----------------- |
|
|
79
|
-
| `@antelopejs/interface-api` | `>=0.0.15 <1.0.0` |
|
|
80
|
-
| `@antelopejs/interface-core` | `>=0.2.4 <1.0.0` |
|
|
86
|
+
<!-- antelopejs-docs-compat:end -->
|
|
81
87
|
|
|
82
88
|
## Contributing
|
|
83
89
|
|
package/dist/antelope.test.js
CHANGED
|
@@ -8,11 +8,7 @@ exports.default = (0, config_1.defineConfig)({
|
|
|
8
8
|
cacheFolder: ".antelope/cache",
|
|
9
9
|
modules: {
|
|
10
10
|
"auth-jwt": {
|
|
11
|
-
source: {
|
|
12
|
-
type: "package",
|
|
13
|
-
package: "@antelopejs/auth-jwt",
|
|
14
|
-
version: "1.0.3",
|
|
15
|
-
},
|
|
11
|
+
source: { type: "local", path: "node_modules/@antelopejs/auth-jwt" },
|
|
16
12
|
config: { secret: "test-secret-key-for-jwt" },
|
|
17
13
|
},
|
|
18
14
|
mongodb: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"antelope.test.js","sourceRoot":"","sources":["../src/antelope.test.ts"],"names":[],"mappings":";;AAAA,2EAA+D;AAC/D,8DAAiE;AAEjE,IAAI,MAAyB,CAAC;AAE9B,kBAAe,IAAA,qBAAY,EAAC;IAC1B,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EAAE,iBAAiB;IAC9B,OAAO,EAAE;QACP,UAAU,EAAE;YACV,MAAM,EAAE
|
|
1
|
+
{"version":3,"file":"antelope.test.js","sourceRoot":"","sources":["../src/antelope.test.ts"],"names":[],"mappings":";;AAAA,2EAA+D;AAC/D,8DAAiE;AAEjE,IAAI,MAAyB,CAAC;AAE9B,kBAAe,IAAA,qBAAY,EAAC;IAC1B,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EAAE,iBAAiB;IAC9B,OAAO,EAAE;QACP,UAAU,EAAE;YACV,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,mCAAmC,EAAE;YACpE,MAAM,EAAE,EAAE,MAAM,EAAE,yBAAyB,EAAE;SAC9C;QACD,OAAO,EAAE;YACP,MAAM,EAAE;gBACN,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,qBAAqB;gBAC9B,OAAO,EAAE,OAAO;aACjB;SACF;QACD,GAAG,EAAE;YACH,MAAM,EAAE;gBACN,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,iBAAiB;gBAC1B,OAAO,EAAE,OAAO;aACjB;YACD,MAAM,EAAE;gBACN,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;gBAC9D,aAAa,EAAE,uBAAuB;aACvC;SACF;KACF;IACD,IAAI,EAAE;QACJ,MAAM,EAAE,YAAY;QACpB,KAAK,CAAC,KAAK;YACT,MAAM,GAAG,MAAM,8CAAiB,CAAC,MAAM,EAAE,CAAC;YAC1C,OAAO;gBACL,OAAO,EAAE;oBACP,OAAO,EAAE;wBACP,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,iBAAiB,EAAE;qBAC9D;iBACF;aACF,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,OAAO;YACX,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACtB,CAAC;KACF;CACF,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import { type Class } from "@antelopejs/interface-core/decorators";
|
|
3
|
+
/**
|
|
4
|
+
* A value JSON can represent: a string, number, boolean, `null`, an array of
|
|
5
|
+
* JSON values, or a {@link JsonObject}. `Date`, `Buffer`, functions and class
|
|
6
|
+
* instances are not JSON values; convert them first (for example
|
|
7
|
+
* `date.toISOString()`).
|
|
8
|
+
*/
|
|
9
|
+
export type JsonValue = string | number | boolean | null | JsonValue[] | JsonObject;
|
|
10
|
+
/**
|
|
11
|
+
* String keys mapped to JSON values. A key whose value is `undefined` is
|
|
12
|
+
* accepted so an optional field can be passed as is; `JSON.stringify` drops
|
|
13
|
+
* it. An object typed as an `interface` is not assignable (it has no index
|
|
14
|
+
* signature); declare it with a `type` alias or spread it into a literal.
|
|
15
|
+
*/
|
|
16
|
+
export type JsonObject = {
|
|
17
|
+
[key: string]: JsonValue | undefined;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* What a verified token yields: the signed string, or the JSON object that was
|
|
21
|
+
* signed. The shape inside the object is not checked by the interface; read it
|
|
22
|
+
* through a parser of your own (see {@link AuthVerifier}).
|
|
23
|
+
*/
|
|
24
|
+
export type AuthClaims = string | JsonObject;
|
|
2
25
|
/**
|
|
3
26
|
* Function type that extracts authentication data from HTTP request.
|
|
4
27
|
*
|
|
@@ -22,11 +45,11 @@ export type AuthSource = (req: IncomingMessage, res: ServerResponse) => string |
|
|
|
22
45
|
*
|
|
23
46
|
* @example
|
|
24
47
|
* ```typescript
|
|
25
|
-
* const
|
|
26
|
-
*
|
|
48
|
+
* const sessionVerifier: AuthVerifier<UserProfile> = async (token, options) =>
|
|
49
|
+
* parseUserProfile(await ValidateRaw(token, options));
|
|
27
50
|
* ```
|
|
28
51
|
*/
|
|
29
|
-
export type AuthVerifier<T =
|
|
52
|
+
export type AuthVerifier<T = AuthClaims> = (data?: string, options?: VerifyOptions) => Promise<T> | T;
|
|
30
53
|
/**
|
|
31
54
|
* Function type that performs additional validation on verified authentication data.
|
|
32
55
|
*
|
|
@@ -41,7 +64,7 @@ export type AuthVerifier<T = unknown> = (data?: string, options?: VerifyOptions)
|
|
|
41
64
|
* profile.roles.includes('admin');
|
|
42
65
|
* ```
|
|
43
66
|
*/
|
|
44
|
-
export type AuthValidator<T =
|
|
67
|
+
export type AuthValidator<T = AuthClaims, R = unknown> = (data: T) => Promise<R> | R;
|
|
45
68
|
/**
|
|
46
69
|
* HTTP Cookie options for controlling how authentication cookies are set.
|
|
47
70
|
*
|
|
@@ -75,6 +98,13 @@ export interface CookieOptions {
|
|
|
75
98
|
domain?: string;
|
|
76
99
|
secure?: boolean;
|
|
77
100
|
}
|
|
101
|
+
type TimeSpanUnit = "Years" | "Year" | "Yrs" | "Yr" | "Y" | "Weeks" | "Week" | "W" | "Days" | "Day" | "D" | "Hours" | "Hour" | "Hrs" | "Hr" | "H" | "Minutes" | "Minute" | "Mins" | "Min" | "M" | "Seconds" | "Second" | "Secs" | "Sec" | "s" | "Milliseconds" | "Millisecond" | "Msecs" | "Msec" | "Ms";
|
|
102
|
+
/**
|
|
103
|
+
* A timespan string in the grammar of the `ms` package: a number, optionally
|
|
104
|
+
* followed by a unit in any case, with or without a space (`"90"`, `"2h"`,
|
|
105
|
+
* `"7 days"`). A bare number string counts milliseconds.
|
|
106
|
+
*/
|
|
107
|
+
export type TimeSpan = `${number}` | `${number}${TimeSpanUnit | Uppercase<TimeSpanUnit> | Lowercase<TimeSpanUnit>}` | `${number} ${TimeSpanUnit | Uppercase<TimeSpanUnit> | Lowercase<TimeSpanUnit>}`;
|
|
78
108
|
/**
|
|
79
109
|
* Options for signing authentication tokens.
|
|
80
110
|
*
|
|
@@ -91,13 +121,13 @@ export interface CookieOptions {
|
|
|
91
121
|
*/
|
|
92
122
|
export interface SignOptions {
|
|
93
123
|
/**
|
|
94
|
-
* Expiration as a number of seconds or a
|
|
124
|
+
* Expiration as a number of seconds or a {@link TimeSpan}.
|
|
95
125
|
*/
|
|
96
|
-
expiresIn?:
|
|
126
|
+
expiresIn?: number | TimeSpan;
|
|
97
127
|
/**
|
|
98
|
-
* Not-before field as a number of seconds or a
|
|
128
|
+
* Not-before field as a number of seconds or a {@link TimeSpan}.
|
|
99
129
|
*/
|
|
100
|
-
notBefore?:
|
|
130
|
+
notBefore?: number | TimeSpan;
|
|
101
131
|
}
|
|
102
132
|
/**
|
|
103
133
|
* Options for verifying authentication tokens.
|
|
@@ -128,21 +158,37 @@ export interface VerifyOptions {
|
|
|
128
158
|
*/
|
|
129
159
|
maxAge?: string | number;
|
|
130
160
|
}
|
|
131
|
-
|
|
132
|
-
|
|
161
|
+
/**
|
|
162
|
+
* What a token signs: a string, a `Buffer`, or a {@link JsonObject}.
|
|
163
|
+
*/
|
|
164
|
+
export type AuthPayload = string | Buffer | JsonObject;
|
|
165
|
+
interface AuthDecoratorOptions<T, R> {
|
|
133
166
|
source?: AuthSource;
|
|
134
|
-
authenticator?: AuthVerifier<T>;
|
|
135
167
|
authenticatorOptions?: VerifyOptions;
|
|
136
168
|
validator?: AuthValidator<T, R>;
|
|
137
169
|
}
|
|
170
|
+
interface DefaultAuthDecoratorCallbacks<R> extends AuthDecoratorOptions<AuthClaims, R> {
|
|
171
|
+
authenticator?: undefined;
|
|
172
|
+
}
|
|
173
|
+
interface CustomAuthDecoratorCallbacks<T, R> extends AuthDecoratorOptions<T, R> {
|
|
174
|
+
authenticator: AuthVerifier<T>;
|
|
175
|
+
}
|
|
176
|
+
interface ResolvedAuthDecoratorCallbacks<T, R> {
|
|
177
|
+
source: AuthSource;
|
|
178
|
+
authenticator: AuthVerifier<T>;
|
|
179
|
+
authenticatorOptions: VerifyOptions;
|
|
180
|
+
validator: AuthValidator<T, R> | undefined;
|
|
181
|
+
}
|
|
182
|
+
declare function buildAuthDecorator<T, R>(callbacks: ResolvedAuthDecoratorCallbacks<T, R>): (validator?: AuthValidator<T, R> | undefined) => import("@antelopejs/interface-core/decorators").PropertyDecorator & import("@antelopejs/interface-core/decorators").ClassDecorator<Class<object, any[]>> & import("@antelopejs/interface-core/decorators").ParameterDecorator;
|
|
183
|
+
type AuthDecoratorFactory<T, R> = ReturnType<typeof buildAuthDecorator<T, R>>;
|
|
138
184
|
/**
|
|
139
185
|
* @internal
|
|
140
186
|
*/
|
|
141
187
|
export declare namespace internal {
|
|
142
|
-
const Verify: (data?: string | undefined, options?: VerifyOptions | undefined) => Promise<
|
|
188
|
+
const Verify: (data?: string | undefined, options?: VerifyOptions | undefined) => Promise<AuthClaims>;
|
|
143
189
|
const Sign: (data: AuthPayload, options?: SignOptions | undefined) => Promise<string>;
|
|
144
190
|
function defaultSource(req: IncomingMessage, _res: ServerResponse): string | undefined;
|
|
145
|
-
const defaultAuthenticator: AuthVerifier
|
|
191
|
+
const defaultAuthenticator: AuthVerifier;
|
|
146
192
|
/**
|
|
147
193
|
* Verifies the signature of signed data attached to the HTTP request and returns the data contained therein.
|
|
148
194
|
*
|
|
@@ -150,29 +196,29 @@ export declare namespace internal {
|
|
|
150
196
|
* @template R - The type of data after validation
|
|
151
197
|
* @param req - HTTP Request
|
|
152
198
|
* @param res - HTTP Response
|
|
153
|
-
* @param
|
|
154
|
-
* @param authenticator - Callback to verify the signature
|
|
155
|
-
* @param authenticatorOptions - Verifier options
|
|
156
|
-
* @param validator - Custom validator callback
|
|
199
|
+
* @param callbacks - The source, the authenticator with its options, and the optional validator, all already resolved
|
|
157
200
|
* @returns The authenticated and validated data
|
|
158
201
|
*/
|
|
159
|
-
function CheckAuthentication<T =
|
|
202
|
+
function CheckAuthentication<T = AuthClaims, R = unknown>(req: IncomingMessage, res: ServerResponse, callbacks: ResolvedAuthDecoratorCallbacks<T, R>): Promise<T | R>;
|
|
160
203
|
}
|
|
161
204
|
/**
|
|
162
205
|
* Verifies the signature of some signed data and returns the data contained therein.
|
|
163
206
|
*
|
|
164
|
-
*
|
|
207
|
+
* The result is the signed string or JSON object ({@link AuthClaims}). Its shape is
|
|
208
|
+
* not checked: parse it into the type you expect before relying on a field.
|
|
209
|
+
*
|
|
165
210
|
* @param token - The signed data token to verify
|
|
166
211
|
* @param options - Options for verification
|
|
167
212
|
* @returns A promise resolving to the verified data
|
|
168
213
|
*
|
|
169
214
|
* @example
|
|
170
215
|
* ```typescript
|
|
171
|
-
* const
|
|
172
|
-
*
|
|
216
|
+
* const claims = await ValidateRaw(authToken, { maxAge: '1h' });
|
|
217
|
+
* const user = parseUserProfile(claims);
|
|
218
|
+
* console.log(user.name);
|
|
173
219
|
* ```
|
|
174
220
|
*/
|
|
175
|
-
export declare function ValidateRaw
|
|
221
|
+
export declare function ValidateRaw(token?: string, options?: VerifyOptions): Promise<AuthClaims>;
|
|
176
222
|
/**
|
|
177
223
|
* Signs some data to create an authentication token.
|
|
178
224
|
*
|
|
@@ -216,8 +262,12 @@ export declare function SignServerResponse(res: ServerResponse, data: AuthPayloa
|
|
|
216
262
|
* A validator must throw to deny access; its return value is injected unchanged.
|
|
217
263
|
* A validator passed to the decorator replaces the configured validator.
|
|
218
264
|
*
|
|
219
|
-
*
|
|
265
|
+
* Without `authenticator`, the default one calls {@link ValidateRaw} and the validator
|
|
266
|
+
* receives an {@link AuthClaims}. With an `authenticator`, `T` is whatever it returns,
|
|
267
|
+
* so a parser written there gives the validator a typed value.
|
|
268
|
+
*
|
|
220
269
|
* @template T - The type of the authenticated data before validation
|
|
270
|
+
* @template R - The type of the final validator result
|
|
221
271
|
* @param callbacks - Configuration object containing callback functions
|
|
222
272
|
* @param callbacks.source - Extracts the signed data from the request
|
|
223
273
|
* @param callbacks.authenticator - Verifies the signature
|
|
@@ -232,11 +282,11 @@ export declare function SignServerResponse(res: ServerResponse, data: AuthPayloa
|
|
|
232
282
|
*
|
|
233
283
|
* // Create a custom auth decorator
|
|
234
284
|
* const RequireAdmin = CreateAuthDecorator({
|
|
235
|
-
* validator: (
|
|
236
|
-
* if (
|
|
285
|
+
* validator: (claims) => {
|
|
286
|
+
* if (typeof claims === 'string' || claims.role !== 'admin') {
|
|
237
287
|
* throw new Error('Admin access required');
|
|
238
288
|
* }
|
|
239
|
-
* return
|
|
289
|
+
* return claims;
|
|
240
290
|
* }
|
|
241
291
|
* });
|
|
242
292
|
*
|
|
@@ -250,7 +300,8 @@ export declare function SignServerResponse(res: ServerResponse, data: AuthPayloa
|
|
|
250
300
|
* }
|
|
251
301
|
* ```
|
|
252
302
|
*/
|
|
253
|
-
export declare function CreateAuthDecorator<R = unknown
|
|
303
|
+
export declare function CreateAuthDecorator<R = unknown>(callbacks: DefaultAuthDecoratorCallbacks<R>): AuthDecoratorFactory<AuthClaims, R>;
|
|
304
|
+
export declare function CreateAuthDecorator<T, R = unknown>(callbacks: CustomAuthDecoratorCallbacks<T, R>): AuthDecoratorFactory<T, R>;
|
|
254
305
|
/**
|
|
255
306
|
* Parameter Provider using the default source and signature verification callbacks.
|
|
256
307
|
* Reads the raw token from x-antelopejs-auth, falling back to ANTELOPEJS_AUTH
|
|
@@ -277,5 +328,5 @@ export declare function CreateAuthDecorator<R = unknown, T = unknown>(callbacks:
|
|
|
277
328
|
*
|
|
278
329
|
* @see {@link CreateAuthDecorator}
|
|
279
330
|
*/
|
|
280
|
-
export declare const Authentication: (validator?: AuthValidator<
|
|
331
|
+
export declare const Authentication: (validator?: AuthValidator<AuthClaims, unknown> | undefined) => import("@antelopejs/interface-core/decorators").PropertyDecorator & import("@antelopejs/interface-core/decorators").ClassDecorator<Class<object, any[]>> & import("@antelopejs/interface-core/decorators").ParameterDecorator;
|
|
281
332
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -15,13 +15,10 @@ const CookieOptionSeparator = "; ";
|
|
|
15
15
|
const ClassParameterProviderSymbolDescription = "authentication-class-provider";
|
|
16
16
|
function readAuthHeader(req) {
|
|
17
17
|
const header = req.headers[AuthHeaderName];
|
|
18
|
-
if (
|
|
19
|
-
return header;
|
|
18
|
+
if (Array.isArray(header)) {
|
|
19
|
+
return header[0];
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
return undefined;
|
|
23
|
-
}
|
|
24
|
-
return header[0];
|
|
21
|
+
return header;
|
|
25
22
|
}
|
|
26
23
|
function readCookieToken(req) {
|
|
27
24
|
const cookieHeader = req.headers.cookie;
|
|
@@ -40,7 +37,7 @@ function serializeCookieOptions(cookieOptions) {
|
|
|
40
37
|
return EmptyString;
|
|
41
38
|
}
|
|
42
39
|
return entries
|
|
43
|
-
.map(([key, value]) =>
|
|
40
|
+
.map(([key, value]) => (value === true ? key : `${key}=${String(value)}`))
|
|
44
41
|
.join(CookieOptionSeparator);
|
|
45
42
|
}
|
|
46
43
|
function createSetCookieHeader(token, cookieOptions) {
|
|
@@ -50,20 +47,44 @@ function createSetCookieHeader(token, cookieOptions) {
|
|
|
50
47
|
}
|
|
51
48
|
return `${AuthCookieName}=${token}; ${serializedCookieOptions}`;
|
|
52
49
|
}
|
|
53
|
-
function resolveAuthDecoratorCallbacks(
|
|
50
|
+
function resolveAuthDecoratorCallbacks(options, authenticator) {
|
|
54
51
|
return {
|
|
55
|
-
source:
|
|
56
|
-
authenticator
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
validator: callbacks.validator,
|
|
52
|
+
source: options.source ?? internal.defaultSource,
|
|
53
|
+
authenticator,
|
|
54
|
+
authenticatorOptions: options.authenticatorOptions ?? {},
|
|
55
|
+
validator: options.validator,
|
|
60
56
|
};
|
|
61
57
|
}
|
|
62
58
|
function createAuthParameterProvider(callbacks, validator) {
|
|
63
|
-
return (context) => internal.CheckAuthentication(context.rawRequest, context.rawResponse,
|
|
59
|
+
return (context) => internal.CheckAuthentication(context.rawRequest, context.rawResponse, {
|
|
60
|
+
...callbacks,
|
|
61
|
+
validator,
|
|
62
|
+
});
|
|
64
63
|
}
|
|
65
|
-
function
|
|
66
|
-
|
|
64
|
+
function isDecoratorTarget(value) {
|
|
65
|
+
return (typeof value === "object" &&
|
|
66
|
+
value !== null &&
|
|
67
|
+
"constructor" in value &&
|
|
68
|
+
typeof value.constructor === "function");
|
|
69
|
+
}
|
|
70
|
+
/** The prototype of the class a class decorator receives, where its handlers' parameters live. */
|
|
71
|
+
function classPrototype(target) {
|
|
72
|
+
const prototype = "prototype" in target ? target.prototype : undefined;
|
|
73
|
+
if (!isDecoratorTarget(prototype)) {
|
|
74
|
+
throw new TypeError("A class decorator applies to a class.");
|
|
75
|
+
}
|
|
76
|
+
return prototype;
|
|
77
|
+
}
|
|
78
|
+
function buildAuthDecorator(callbacks) {
|
|
79
|
+
return (0, decorators_1.MakeParameterAndPropertyAndClassDecorator)((target, key, index, validator) => {
|
|
80
|
+
const authValidator = validator ?? callbacks.validator;
|
|
81
|
+
const provider = createAuthParameterProvider(callbacks, authValidator);
|
|
82
|
+
if (key === undefined) {
|
|
83
|
+
(0, interface_api_1.SetParameterProvider)(classPrototype(target), Symbol(ClassParameterProviderSymbolDescription), undefined, provider);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
(0, interface_api_1.SetParameterProvider)(target, key, index, provider);
|
|
87
|
+
});
|
|
67
88
|
}
|
|
68
89
|
/**
|
|
69
90
|
* @internal
|
|
@@ -84,13 +105,11 @@ var internal;
|
|
|
84
105
|
* @template R - The type of data after validation
|
|
85
106
|
* @param req - HTTP Request
|
|
86
107
|
* @param res - HTTP Response
|
|
87
|
-
* @param
|
|
88
|
-
* @param authenticator - Callback to verify the signature
|
|
89
|
-
* @param authenticatorOptions - Verifier options
|
|
90
|
-
* @param validator - Custom validator callback
|
|
108
|
+
* @param callbacks - The source, the authenticator with its options, and the optional validator, all already resolved
|
|
91
109
|
* @returns The authenticated and validated data
|
|
92
110
|
*/
|
|
93
|
-
async function CheckAuthentication(req, res,
|
|
111
|
+
async function CheckAuthentication(req, res, callbacks) {
|
|
112
|
+
const { source, authenticator, authenticatorOptions, validator } = callbacks;
|
|
94
113
|
const verifiedData = await authenticator(source(req, res), authenticatorOptions);
|
|
95
114
|
if (!validator) {
|
|
96
115
|
return verifiedData;
|
|
@@ -102,15 +121,18 @@ var internal;
|
|
|
102
121
|
/**
|
|
103
122
|
* Verifies the signature of some signed data and returns the data contained therein.
|
|
104
123
|
*
|
|
105
|
-
*
|
|
124
|
+
* The result is the signed string or JSON object ({@link AuthClaims}). Its shape is
|
|
125
|
+
* not checked: parse it into the type you expect before relying on a field.
|
|
126
|
+
*
|
|
106
127
|
* @param token - The signed data token to verify
|
|
107
128
|
* @param options - Options for verification
|
|
108
129
|
* @returns A promise resolving to the verified data
|
|
109
130
|
*
|
|
110
131
|
* @example
|
|
111
132
|
* ```typescript
|
|
112
|
-
* const
|
|
113
|
-
*
|
|
133
|
+
* const claims = await ValidateRaw(authToken, { maxAge: '1h' });
|
|
134
|
+
* const user = parseUserProfile(claims);
|
|
135
|
+
* console.log(user.name);
|
|
114
136
|
* ```
|
|
115
137
|
*/
|
|
116
138
|
function ValidateRaw(token, options) {
|
|
@@ -158,59 +180,11 @@ function SignServerResponse(res, data, signOptions, cookieOptions) {
|
|
|
158
180
|
return res;
|
|
159
181
|
});
|
|
160
182
|
}
|
|
161
|
-
/**
|
|
162
|
-
* Creates a Parameter Provider using the specified source and signature verification callbacks.
|
|
163
|
-
*
|
|
164
|
-
* The callbacks are processed in the following order:
|
|
165
|
-
* `source(req, res)` => `authenticator(prev, authenticatorOptions)` => `validator(prev)` => Parameter
|
|
166
|
-
* A validator must throw to deny access; its return value is injected unchanged.
|
|
167
|
-
* A validator passed to the decorator replaces the configured validator.
|
|
168
|
-
*
|
|
169
|
-
* @template R - The type of the final validator result
|
|
170
|
-
* @template T - The type of the authenticated data before validation
|
|
171
|
-
* @param callbacks - Configuration object containing callback functions
|
|
172
|
-
* @param callbacks.source - Extracts the signed data from the request
|
|
173
|
-
* @param callbacks.authenticator - Verifies the signature
|
|
174
|
-
* @param callbacks.authenticatorOptions - Options for verification
|
|
175
|
-
* @param callbacks.validator - Custom validation step (overrideable with decorator call)
|
|
176
|
-
* @returns A decorator for parameters, properties, and classes
|
|
177
|
-
*
|
|
178
|
-
* @example
|
|
179
|
-
* ```typescript
|
|
180
|
-
* import { Controller, Get } from '@antelopejs/interface-api';
|
|
181
|
-
* import { CreateAuthDecorator } from '@antelopejs/interface-auth';
|
|
182
|
-
*
|
|
183
|
-
* // Create a custom auth decorator
|
|
184
|
-
* const RequireAdmin = CreateAuthDecorator({
|
|
185
|
-
* validator: (user: any) => {
|
|
186
|
-
* if (!user || user.role !== 'admin') {
|
|
187
|
-
* throw new Error('Admin access required');
|
|
188
|
-
* }
|
|
189
|
-
* return user;
|
|
190
|
-
* }
|
|
191
|
-
* });
|
|
192
|
-
*
|
|
193
|
-
* // Use the decorator
|
|
194
|
-
* class AdminController extends Controller('/admin') {
|
|
195
|
-
* @Get('settings')
|
|
196
|
-
* getSettings(@RequireAdmin() user: { role: string }) {
|
|
197
|
-
* // Only admin users can access this
|
|
198
|
-
* return { role: user.role };
|
|
199
|
-
* }
|
|
200
|
-
* }
|
|
201
|
-
* ```
|
|
202
|
-
*/
|
|
203
183
|
function CreateAuthDecorator(callbacks) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if (key === undefined) {
|
|
209
|
-
registerClassParameterProvider(target, provider);
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
(0, interface_api_1.SetParameterProvider)(target, key, index, provider);
|
|
213
|
-
});
|
|
184
|
+
if (callbacks.authenticator) {
|
|
185
|
+
return buildAuthDecorator(resolveAuthDecoratorCallbacks(callbacks, callbacks.authenticator));
|
|
186
|
+
}
|
|
187
|
+
return buildAuthDecorator(resolveAuthDecoratorCallbacks(callbacks, ValidateRaw));
|
|
214
188
|
}
|
|
215
189
|
/**
|
|
216
190
|
* Parameter Provider using the default source and signature verification callbacks.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const chai_1 = require("chai");
|
|
4
|
+
const __1 = require("..");
|
|
5
|
+
class Guarded {
|
|
6
|
+
}
|
|
7
|
+
const WITHOUT_PROTOTYPE = Guarded.bind(null);
|
|
8
|
+
describe("class decorator target", () => {
|
|
9
|
+
it("refuses a class that has no prototype object", () => {
|
|
10
|
+
(0, chai_1.expect)(() => {
|
|
11
|
+
(0, __1.Authentication)()(WITHOUT_PROTOTYPE);
|
|
12
|
+
}).to.throw(TypeError, "A class decorator applies to a class.");
|
|
13
|
+
});
|
|
14
|
+
it("accepts a class with a prototype object", () => {
|
|
15
|
+
(0, chai_1.expect)(() => {
|
|
16
|
+
(0, __1.Authentication)()(Guarded);
|
|
17
|
+
}).not.to.throw();
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=class-decorator.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"class-decorator.test.js","sourceRoot":"","sources":["../../src/tests/class-decorator.test.ts"],"names":[],"mappings":";;AAAA,+BAA8B;AAC9B,0BAAoC;AAEpC,MAAM,OAAO;CAAG;AAEhB,MAAM,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAE7C,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,IAAA,aAAM,EAAC,GAAG,EAAE;YACV,IAAA,kBAAc,GAAE,CAAC,iBAAiB,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,uCAAuC,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,IAAA,aAAM,EAAC,GAAG,EAAE;YACV,IAAA,kBAAc,GAAE,CAAC,OAAO,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/tests/index.test.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const chai_1 = require("chai");
|
|
4
4
|
const interface_api_1 = require("@antelopejs/interface-api");
|
|
5
|
-
const
|
|
5
|
+
const __1 = require("..");
|
|
6
6
|
const testUsers = {
|
|
7
7
|
default: {
|
|
8
8
|
name: "Bob",
|
|
@@ -16,61 +16,36 @@ const testUsers = {
|
|
|
16
16
|
},
|
|
17
17
|
};
|
|
18
18
|
describe("JWT Authentication Tests", () => {
|
|
19
|
-
it("jwt token is valid", async () =>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
it("jwt token is valid", async () => {
|
|
20
|
+
const userData = testUsers.default;
|
|
21
|
+
const token = await (0, __1.SignRaw)(userData, { expiresIn: "1h" });
|
|
22
|
+
const verifiedData = await (0, __1.ValidateRaw)(token);
|
|
23
|
+
(0, chai_1.expect)(verifiedData).to.be.an("object");
|
|
24
|
+
(0, chai_1.expect)(verifiedData).to.have.property("name", userData.name);
|
|
25
|
+
(0, chai_1.expect)(verifiedData).to.have.property("email", userData.email);
|
|
26
|
+
(0, chai_1.expect)(verifiedData).to.have.property("password", userData.password);
|
|
27
|
+
});
|
|
28
|
+
it("jwt token is invalid", async () => {
|
|
29
|
+
const invalidToken = "invalid.jwt.token";
|
|
30
|
+
try {
|
|
31
|
+
await (0, __1.ValidateRaw)(invalidToken);
|
|
32
|
+
chai_1.expect.fail("Should have thrown an error for invalid token");
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
(0, chai_1.expect)(error).to.be.instanceOf(interface_api_1.HTTPResult);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
it("jwt token is expired", async () => {
|
|
39
|
+
const userData = testUsers.default;
|
|
40
|
+
const token = await (0, __1.SignRaw)(userData, { expiresIn: "1ms" });
|
|
41
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
42
|
+
try {
|
|
43
|
+
await (0, __1.ValidateRaw)(token);
|
|
44
|
+
chai_1.expect.fail("Should have thrown an error for expired token");
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
(0, chai_1.expect)(error).to.be.instanceOf(interface_api_1.HTTPResult);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
23
50
|
});
|
|
24
|
-
async function jwtTokenIsValid() {
|
|
25
|
-
const userData = testUsers.default;
|
|
26
|
-
const token = await (0, interface_auth_1.SignRaw)(userData, { expiresIn: "1h" });
|
|
27
|
-
const verifiedData = await (0, interface_auth_1.ValidateRaw)(token);
|
|
28
|
-
(0, chai_1.expect)(verifiedData).to.be.an("object");
|
|
29
|
-
(0, chai_1.expect)(verifiedData).to.have.property("name", userData.name);
|
|
30
|
-
(0, chai_1.expect)(verifiedData).to.have.property("email", userData.email);
|
|
31
|
-
(0, chai_1.expect)(verifiedData).to.have.property("password", userData.password);
|
|
32
|
-
}
|
|
33
|
-
async function jwtTokenIsInvalid() {
|
|
34
|
-
const invalidToken = "invalid.jwt.token";
|
|
35
|
-
try {
|
|
36
|
-
await (0, interface_auth_1.ValidateRaw)(invalidToken);
|
|
37
|
-
chai_1.expect.fail("Should have thrown an error for invalid token");
|
|
38
|
-
}
|
|
39
|
-
catch (error) {
|
|
40
|
-
(0, chai_1.expect)(error).to.be.instanceOf(interface_api_1.HTTPResult);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
async function jwtTokenIsExpired() {
|
|
44
|
-
const userData = testUsers.default;
|
|
45
|
-
const token = await (0, interface_auth_1.SignRaw)(userData, { expiresIn: "1ms" });
|
|
46
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
47
|
-
try {
|
|
48
|
-
await (0, interface_auth_1.ValidateRaw)(token);
|
|
49
|
-
chai_1.expect.fail("Should have thrown an error for expired token");
|
|
50
|
-
}
|
|
51
|
-
catch (error) {
|
|
52
|
-
(0, chai_1.expect)(error).to.be.instanceOf(interface_api_1.HTTPResult);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
async function setCookieUsesStandaloneBooleanDirectives() {
|
|
56
|
-
const headers = {};
|
|
57
|
-
const responseLike = {
|
|
58
|
-
setHeader(name, value) {
|
|
59
|
-
headers[name.toLowerCase()] = normalizeHeaderValue(value);
|
|
60
|
-
return responseLike;
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
await (0, interface_auth_1.SignServerResponse)(responseLike, { userId: "user-7" }, { expiresIn: "1h" }, { httpOnly: true });
|
|
64
|
-
const setCookieHeader = headers["set-cookie"];
|
|
65
|
-
(0, chai_1.expect)(setCookieHeader).to.be.a("string");
|
|
66
|
-
(0, chai_1.expect)(setCookieHeader).to.match(/^ANTELOPEJS_AUTH=/);
|
|
67
|
-
(0, chai_1.expect)(setCookieHeader).to.match(/httpOnly/);
|
|
68
|
-
(0, chai_1.expect)(setCookieHeader).to.not.match(/httpOnly=true/);
|
|
69
|
-
}
|
|
70
|
-
function normalizeHeaderValue(value) {
|
|
71
|
-
if (Array.isArray(value)) {
|
|
72
|
-
return value.join(",");
|
|
73
|
-
}
|
|
74
|
-
return String(value);
|
|
75
|
-
}
|
|
76
51
|
//# sourceMappingURL=index.test.js.map
|