@antelopejs/interface-auth 0.0.6 → 0.0.7
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 +79 -16
- package/dist/antelope.test.js +6 -12
- package/dist/antelope.test.js.map +1 -1
- package/dist/index.d.ts +28 -22
- package/dist/index.js +22 -19
- package/dist/index.js.map +1 -1
- package/dist/tests/index.test.js +1 -1
- package/dist/tests/index.test.js.map +1 -1
- package/docs/2.authentication.md +35 -19
- package/docs/3.token-handling.md +31 -29
- package/docs/4.parameter-decoration.md +14 -12
- package/docs/tsconfig.json +12 -0
- package/package.json +35 -20
- package/skills/auth-interface/SKILL.md +16 -6
package/README.md
CHANGED
|
@@ -1,31 +1,94 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
# Interface Auth
|
|
1
|
+
# @antelopejs/interface-auth
|
|
4
2
|
|
|
5
3
|
<div align="center">
|
|
6
|
-
<a href="https://www.npmjs.com/package/@antelopejs/interface-auth"><img src="https://img.shields.io/npm/v/@antelopejs/interface-auth?style=for-the-badge&labelColor=000000&color=000000"
|
|
7
|
-
<a href="./LICENSE"><img alt="License" src="https://img.shields.io/
|
|
8
|
-
<a href="https://discord.gg/sjK28QHrA7"><img src="https://img.shields.io/badge/Discord-18181B?logo=discord&style=for-the-badge&color=000000"
|
|
9
|
-
<a href="
|
|
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/sjK28QHrA7"><img 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 alt="Docs" src="https://img.shields.io/badge/Docs-18181B?style=for-the-badge&color=000000"></a>
|
|
10
8
|
</div>
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
The AntelopeJS contract for token authentication: sign and verify tokens, and inject the verified payload into API handlers with a decorator.
|
|
11
|
+
|
|
12
|
+
## What it offers
|
|
13
|
+
|
|
14
|
+
- `SignRaw` and `ValidateRaw` sign a payload into a token and verify a token back into its payload.
|
|
15
|
+
- `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, falling back to the `ANTELOPEJS_AUTH` cookie when the header is absent, verifies it and injects the payload into a handler parameter.
|
|
17
|
+
- `CreateAuthDecorator` builds your own decorator with a custom source, verifier and validator.
|
|
18
|
+
|
|
19
|
+
## Implementations
|
|
13
20
|
|
|
14
|
-
|
|
21
|
+
| Module | Notes |
|
|
22
|
+
| ---------------------------------------------------------------- | --------------- |
|
|
23
|
+
| [`@antelopejs/auth-jwt`](https://github.com/AntelopeJS/auth-jwt) | JSON Web Tokens |
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
Add the interface to the module that protects routes:
|
|
15
28
|
|
|
16
29
|
```bash
|
|
17
|
-
|
|
30
|
+
pnpm add @antelopejs/interface-auth
|
|
18
31
|
```
|
|
19
32
|
|
|
33
|
+
Then add an implementation to the project, with an implementation of the API interface:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
ajs project modules add @antelopejs/auth-jwt @antelopejs/api
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick start
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { Controller, Get, Post } from "@antelopejs/interface-api";
|
|
43
|
+
import { Authentication, SignRaw } from "@antelopejs/interface-auth";
|
|
44
|
+
|
|
45
|
+
interface Session {
|
|
46
|
+
id: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class SessionController extends Controller("/session") {
|
|
50
|
+
@Post("login")
|
|
51
|
+
async login() {
|
|
52
|
+
return SignRaw({ id: "user-7" }, { expiresIn: "1h" });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@Get("me")
|
|
56
|
+
async me(@Authentication() session: Session) {
|
|
57
|
+
return { id: session.id };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
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 demonstrates signing; validate credentials before issuing tokens in a real application.
|
|
63
|
+
|
|
20
64
|
## Documentation
|
|
21
65
|
|
|
22
|
-
|
|
66
|
+
- [Introduction](./docs/1.introduction.md)
|
|
67
|
+
- [Authentication](./docs/2.authentication.md)
|
|
68
|
+
- [Token handling](./docs/3.token-handling.md)
|
|
69
|
+
- [Parameter decoration](./docs/4.parameter-decoration.md)
|
|
70
|
+
|
|
71
|
+
## Compatibility
|
|
72
|
+
|
|
73
|
+
Use with `@antelopejs/core` 1.x and the following peer dependencies:
|
|
23
74
|
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
75
|
+
<!-- docs-compat: ./package.json#peerDependencies -->
|
|
76
|
+
|
|
77
|
+
| Package | Range |
|
|
78
|
+
| ---------------------------- | ----------------- |
|
|
79
|
+
| `@antelopejs/interface-api` | `>=0.0.15 <1.0.0` |
|
|
80
|
+
| `@antelopejs/interface-core` | `>=0.2.4 <1.0.0` |
|
|
81
|
+
|
|
82
|
+
## Contributing
|
|
83
|
+
|
|
84
|
+
Read [CONTRIBUTING.md](./CONTRIBUTING.md) before you open a pull request. The local checks are:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
pnpm install
|
|
88
|
+
pnpm lint
|
|
89
|
+
pnpm test
|
|
90
|
+
```
|
|
28
91
|
|
|
29
92
|
## License
|
|
30
93
|
|
|
31
|
-
|
|
94
|
+
[Apache-2.0](./LICENSE)
|
package/dist/antelope.test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const config_1 = require("@antelopejs/interface-core/config");
|
|
4
3
|
const mongodb_memory_server_core_1 = require("mongodb-memory-server-core");
|
|
4
|
+
const config_1 = require("@antelopejs/interface-core/config");
|
|
5
5
|
let mongod;
|
|
6
6
|
exports.default = (0, config_1.defineConfig)({
|
|
7
7
|
name: "interface-auth-test",
|
|
@@ -11,7 +11,7 @@ exports.default = (0, config_1.defineConfig)({
|
|
|
11
11
|
source: {
|
|
12
12
|
type: "package",
|
|
13
13
|
package: "@antelopejs/auth-jwt",
|
|
14
|
-
version: "1.0.
|
|
14
|
+
version: "1.0.3",
|
|
15
15
|
},
|
|
16
16
|
config: { secret: "test-secret-key-for-jwt" },
|
|
17
17
|
},
|
|
@@ -19,24 +19,18 @@ exports.default = (0, config_1.defineConfig)({
|
|
|
19
19
|
source: {
|
|
20
20
|
type: "package",
|
|
21
21
|
package: "@antelopejs/mongodb",
|
|
22
|
-
version: "1.
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
database_decorators: {
|
|
26
|
-
source: {
|
|
27
|
-
type: "package",
|
|
28
|
-
package: "@antelopejs/database-decorators",
|
|
29
|
-
version: "1.0.0",
|
|
22
|
+
version: "1.3.1",
|
|
30
23
|
},
|
|
31
24
|
},
|
|
32
25
|
api: {
|
|
33
26
|
source: {
|
|
34
27
|
type: "package",
|
|
35
28
|
package: "@antelopejs/api",
|
|
36
|
-
version: "1.
|
|
29
|
+
version: "1.3.0",
|
|
37
30
|
},
|
|
38
31
|
config: {
|
|
39
32
|
servers: [{ protocol: "http", host: "127.0.0.1", port: 5010 }],
|
|
33
|
+
publicBaseUrl: "http://127.0.0.1:5010",
|
|
40
34
|
},
|
|
41
35
|
},
|
|
42
36
|
},
|
|
@@ -47,7 +41,7 @@ exports.default = (0, config_1.defineConfig)({
|
|
|
47
41
|
return {
|
|
48
42
|
modules: {
|
|
49
43
|
mongodb: {
|
|
50
|
-
config: { url: mongod.getUri() },
|
|
44
|
+
config: { url: mongod.getUri(), database: "antelopejs_test" },
|
|
51
45
|
},
|
|
52
46
|
},
|
|
53
47
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"antelope.test.js","sourceRoot":"","sources":["../src/antelope.test.ts"],"names":[],"mappings":";;AAAA,
|
|
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;gBACN,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,sBAAsB;gBAC/B,OAAO,EAAE,OAAO;aACjB;YACD,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
|
@@ -45,9 +45,13 @@ export type AuthValidator<T = unknown, R = unknown> = (data: T) => Promise<R> |
|
|
|
45
45
|
/**
|
|
46
46
|
* HTTP Cookie options for controlling how authentication cookies are set.
|
|
47
47
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
48
|
+
* Keys are serialized literally. False and undefined values are omitted;
|
|
49
|
+
* true values become standalone directives, and other values use String(value).
|
|
50
|
+
* No attributes are supplied by default.
|
|
51
|
+
*
|
|
52
|
+
* @property maxAge - Serialized as maxAge, not the standard Max-Age attribute
|
|
53
|
+
* @property signed - Serialized as a directive; does not add a cookie signature
|
|
54
|
+
* @property expires - Serialized with String(date), not an HTTP-date formatter
|
|
51
55
|
* @property httpOnly - Whether the cookie is only accessible via HTTP(S) and not client JavaScript
|
|
52
56
|
* @property path - URL path for which the cookie is valid
|
|
53
57
|
* @property domain - Domain for which the cookie is valid
|
|
@@ -58,7 +62,6 @@ export type AuthValidator<T = unknown, R = unknown> = (data: T) => Promise<R> |
|
|
|
58
62
|
* const secureOptions: CookieOptions = {
|
|
59
63
|
* httpOnly: true,
|
|
60
64
|
* secure: true,
|
|
61
|
-
* maxAge: 3600000, // 1 hour
|
|
62
65
|
* path: '/'
|
|
63
66
|
* };
|
|
64
67
|
* ```
|
|
@@ -185,6 +188,8 @@ export declare function ValidateRaw<T = unknown>(token?: string, options?: Verif
|
|
|
185
188
|
export declare function SignRaw(data: AuthPayload, options?: SignOptions): Promise<string>;
|
|
186
189
|
/**
|
|
187
190
|
* Signs some data and attaches it to an HTTP Response object as a cookie.
|
|
191
|
+
* Replaces the Set-Cookie header with ANTELOPEJS_AUTH and the supplied attributes.
|
|
192
|
+
* Does not send or end the response. See {@link CookieOptions} for serialization limits.
|
|
188
193
|
*
|
|
189
194
|
* @param res - HTTP Response object to set the cookie on
|
|
190
195
|
* @param data - Data to sign and attach
|
|
@@ -208,6 +213,8 @@ export declare function SignServerResponse(res: ServerResponse, data: AuthPayloa
|
|
|
208
213
|
*
|
|
209
214
|
* The callbacks are processed in the following order:
|
|
210
215
|
* `source(req, res)` => `authenticator(prev, authenticatorOptions)` => `validator(prev)` => Parameter
|
|
216
|
+
* A validator must throw to deny access; its return value is injected unchanged.
|
|
217
|
+
* A validator passed to the decorator replaces the configured validator.
|
|
211
218
|
*
|
|
212
219
|
* @template R - The type of the final validator result
|
|
213
220
|
* @template T - The type of the authenticated data before validation
|
|
@@ -216,10 +223,13 @@ export declare function SignServerResponse(res: ServerResponse, data: AuthPayloa
|
|
|
216
223
|
* @param callbacks.authenticator - Verifies the signature
|
|
217
224
|
* @param callbacks.authenticatorOptions - Options for verification
|
|
218
225
|
* @param callbacks.validator - Custom validation step (overrideable with decorator call)
|
|
219
|
-
* @returns A decorator for parameters,
|
|
226
|
+
* @returns A decorator for parameters, properties, and classes
|
|
220
227
|
*
|
|
221
228
|
* @example
|
|
222
229
|
* ```typescript
|
|
230
|
+
* import { Controller, Get } from '@antelopejs/interface-api';
|
|
231
|
+
* import { CreateAuthDecorator } from '@antelopejs/interface-auth';
|
|
232
|
+
*
|
|
223
233
|
* // Create a custom auth decorator
|
|
224
234
|
* const RequireAdmin = CreateAuthDecorator({
|
|
225
235
|
* validator: (user: any) => {
|
|
@@ -231,11 +241,11 @@ export declare function SignServerResponse(res: ServerResponse, data: AuthPayloa
|
|
|
231
241
|
* });
|
|
232
242
|
*
|
|
233
243
|
* // Use the decorator
|
|
234
|
-
* class AdminController {
|
|
235
|
-
* @
|
|
236
|
-
* getSettings(@RequireAdmin() user:
|
|
244
|
+
* class AdminController extends Controller('/admin') {
|
|
245
|
+
* @Get('settings')
|
|
246
|
+
* getSettings(@RequireAdmin() user: { role: string }) {
|
|
237
247
|
* // Only admin users can access this
|
|
238
|
-
* return {
|
|
248
|
+
* return { role: user.role };
|
|
239
249
|
* }
|
|
240
250
|
* }
|
|
241
251
|
* ```
|
|
@@ -243,7 +253,9 @@ export declare function SignServerResponse(res: ServerResponse, data: AuthPayloa
|
|
|
243
253
|
export declare function CreateAuthDecorator<R = unknown, T = unknown>(callbacks: AuthDecoratorCallbacks<T, R>): (validator?: AuthValidator<T, R> | undefined) => import("@antelopejs/interface-core/decorators").ClassDecorator<import("@antelopejs/interface-core/decorators").Class<any, any[]>> & import("@antelopejs/interface-core/decorators").PropertyDecorator & import("@antelopejs/interface-core/decorators").ParameterDecorator;
|
|
244
254
|
/**
|
|
245
255
|
* Parameter Provider using the default source and signature verification callbacks.
|
|
246
|
-
*
|
|
256
|
+
* Reads the raw token from x-antelopejs-auth, falling back to ANTELOPEJS_AUTH
|
|
257
|
+
* only when the header is absent. Does not read Authorization or strip Bearer.
|
|
258
|
+
* This decorator can be applied to parameters, properties, or classes to
|
|
247
259
|
* require authentication.
|
|
248
260
|
*
|
|
249
261
|
* @param validator - Optional custom validation callback
|
|
@@ -251,21 +263,15 @@ export declare function CreateAuthDecorator<R = unknown, T = unknown>(callbacks:
|
|
|
251
263
|
*
|
|
252
264
|
* @example
|
|
253
265
|
* ```typescript
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
266
|
+
* import { Controller, Get } from '@antelopejs/interface-api';
|
|
267
|
+
* import { Authentication } from '@antelopejs/interface-auth';
|
|
268
|
+
*
|
|
269
|
+
* class UserController extends Controller('/users') {
|
|
270
|
+
* @Get('profile')
|
|
271
|
+
* getProfile(@Authentication() user: { name: string; email: string }) {
|
|
257
272
|
* // 'user' contains the authenticated user data
|
|
258
273
|
* return { name: user.name, email: user.email };
|
|
259
274
|
* }
|
|
260
|
-
*
|
|
261
|
-
* @Route('/admin')
|
|
262
|
-
* adminPage(@Authentication((user) => {
|
|
263
|
-
* if (user.role !== 'admin') throw new Error('Admin only');
|
|
264
|
-
* return user;
|
|
265
|
-
* }) user: UserProfile) {
|
|
266
|
-
* // Only admins will reach this code
|
|
267
|
-
* return { adminData: this.sensitiveData };
|
|
268
|
-
* }
|
|
269
275
|
* }
|
|
270
276
|
* ```
|
|
271
277
|
*
|
package/dist/index.js
CHANGED
|
@@ -5,8 +5,8 @@ exports.ValidateRaw = ValidateRaw;
|
|
|
5
5
|
exports.SignRaw = SignRaw;
|
|
6
6
|
exports.SignServerResponse = SignServerResponse;
|
|
7
7
|
exports.CreateAuthDecorator = CreateAuthDecorator;
|
|
8
|
-
const interface_api_1 = require("@antelopejs/interface-api");
|
|
9
8
|
const interface_core_1 = require("@antelopejs/interface-core");
|
|
9
|
+
const interface_api_1 = require("@antelopejs/interface-api");
|
|
10
10
|
const decorators_1 = require("@antelopejs/interface-core/decorators");
|
|
11
11
|
const AuthHeaderName = "x-antelopejs-auth";
|
|
12
12
|
const AuthCookieName = "ANTELOPEJS_AUTH";
|
|
@@ -133,6 +133,8 @@ function SignRaw(data, options) {
|
|
|
133
133
|
}
|
|
134
134
|
/**
|
|
135
135
|
* Signs some data and attaches it to an HTTP Response object as a cookie.
|
|
136
|
+
* Replaces the Set-Cookie header with ANTELOPEJS_AUTH and the supplied attributes.
|
|
137
|
+
* Does not send or end the response. See {@link CookieOptions} for serialization limits.
|
|
136
138
|
*
|
|
137
139
|
* @param res - HTTP Response object to set the cookie on
|
|
138
140
|
* @param data - Data to sign and attach
|
|
@@ -161,6 +163,8 @@ function SignServerResponse(res, data, signOptions, cookieOptions) {
|
|
|
161
163
|
*
|
|
162
164
|
* The callbacks are processed in the following order:
|
|
163
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.
|
|
164
168
|
*
|
|
165
169
|
* @template R - The type of the final validator result
|
|
166
170
|
* @template T - The type of the authenticated data before validation
|
|
@@ -169,10 +173,13 @@ function SignServerResponse(res, data, signOptions, cookieOptions) {
|
|
|
169
173
|
* @param callbacks.authenticator - Verifies the signature
|
|
170
174
|
* @param callbacks.authenticatorOptions - Options for verification
|
|
171
175
|
* @param callbacks.validator - Custom validation step (overrideable with decorator call)
|
|
172
|
-
* @returns A decorator for parameters,
|
|
176
|
+
* @returns A decorator for parameters, properties, and classes
|
|
173
177
|
*
|
|
174
178
|
* @example
|
|
175
179
|
* ```typescript
|
|
180
|
+
* import { Controller, Get } from '@antelopejs/interface-api';
|
|
181
|
+
* import { CreateAuthDecorator } from '@antelopejs/interface-auth';
|
|
182
|
+
*
|
|
176
183
|
* // Create a custom auth decorator
|
|
177
184
|
* const RequireAdmin = CreateAuthDecorator({
|
|
178
185
|
* validator: (user: any) => {
|
|
@@ -184,11 +191,11 @@ function SignServerResponse(res, data, signOptions, cookieOptions) {
|
|
|
184
191
|
* });
|
|
185
192
|
*
|
|
186
193
|
* // Use the decorator
|
|
187
|
-
* class AdminController {
|
|
188
|
-
* @
|
|
189
|
-
* getSettings(@RequireAdmin() user:
|
|
194
|
+
* class AdminController extends Controller('/admin') {
|
|
195
|
+
* @Get('settings')
|
|
196
|
+
* getSettings(@RequireAdmin() user: { role: string }) {
|
|
190
197
|
* // Only admin users can access this
|
|
191
|
-
* return {
|
|
198
|
+
* return { role: user.role };
|
|
192
199
|
* }
|
|
193
200
|
* }
|
|
194
201
|
* ```
|
|
@@ -207,7 +214,9 @@ function CreateAuthDecorator(callbacks) {
|
|
|
207
214
|
}
|
|
208
215
|
/**
|
|
209
216
|
* Parameter Provider using the default source and signature verification callbacks.
|
|
210
|
-
*
|
|
217
|
+
* Reads the raw token from x-antelopejs-auth, falling back to ANTELOPEJS_AUTH
|
|
218
|
+
* only when the header is absent. Does not read Authorization or strip Bearer.
|
|
219
|
+
* This decorator can be applied to parameters, properties, or classes to
|
|
211
220
|
* require authentication.
|
|
212
221
|
*
|
|
213
222
|
* @param validator - Optional custom validation callback
|
|
@@ -215,21 +224,15 @@ function CreateAuthDecorator(callbacks) {
|
|
|
215
224
|
*
|
|
216
225
|
* @example
|
|
217
226
|
* ```typescript
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
227
|
+
* import { Controller, Get } from '@antelopejs/interface-api';
|
|
228
|
+
* import { Authentication } from '@antelopejs/interface-auth';
|
|
229
|
+
*
|
|
230
|
+
* class UserController extends Controller('/users') {
|
|
231
|
+
* @Get('profile')
|
|
232
|
+
* getProfile(@Authentication() user: { name: string; email: string }) {
|
|
221
233
|
* // 'user' contains the authenticated user data
|
|
222
234
|
* return { name: user.name, email: user.email };
|
|
223
235
|
* }
|
|
224
|
-
*
|
|
225
|
-
* @Route('/admin')
|
|
226
|
-
* adminPage(@Authentication((user) => {
|
|
227
|
-
* if (user.role !== 'admin') throw new Error('Admin only');
|
|
228
|
-
* return user;
|
|
229
|
-
* }) user: UserProfile) {
|
|
230
|
-
* // Only admins will reach this code
|
|
231
|
-
* return { adminData: this.sensitiveData };
|
|
232
|
-
* }
|
|
233
236
|
* }
|
|
234
237
|
* ```
|
|
235
238
|
*
|
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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"}
|
package/dist/tests/index.test.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const chai_1 = require("chai");
|
|
3
4
|
const interface_api_1 = require("@antelopejs/interface-api");
|
|
4
5
|
const interface_auth_1 = require("@antelopejs/interface-auth");
|
|
5
|
-
const chai_1 = require("chai");
|
|
6
6
|
const testUsers = {
|
|
7
7
|
default: {
|
|
8
8
|
name: "Bob",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/tests/index.test.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/tests/index.test.ts"],"names":[],"mappings":"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"}
|
package/docs/2.authentication.md
CHANGED
|
@@ -15,7 +15,13 @@ A typical authentication flow consists of four steps:
|
|
|
15
15
|
|
|
16
16
|
```typescript
|
|
17
17
|
import { SignRaw, Authentication } from "@antelopejs/interface-auth";
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
Controller,
|
|
20
|
+
Post,
|
|
21
|
+
Get,
|
|
22
|
+
JSONBody,
|
|
23
|
+
HTTPResult,
|
|
24
|
+
} from "@antelopejs/interface-api";
|
|
19
25
|
|
|
20
26
|
class UserController extends Controller("/users") {
|
|
21
27
|
@Post("login")
|
|
@@ -61,11 +67,13 @@ An `AuthSource` function extracts the authentication token from the incoming HTT
|
|
|
61
67
|
1. **Custom header** - The `x-antelopejs-auth` header
|
|
62
68
|
2. **Cookie** - The `ANTELOPEJS_AUTH` cookie
|
|
63
69
|
|
|
70
|
+
The header contains the raw token, not `Bearer <token>`. A present header takes precedence even when it is empty or invalid; authentication does not retry with the cookie after verification fails. The default source does not read `Authorization`.
|
|
71
|
+
|
|
64
72
|
### Create a custom source
|
|
65
73
|
|
|
66
74
|
Implement the `AuthSource` type to extract tokens from a different location.
|
|
67
75
|
|
|
68
|
-
```
|
|
76
|
+
```ts docs-check
|
|
69
77
|
import { CreateAuthDecorator, AuthSource } from "@antelopejs/interface-auth";
|
|
70
78
|
import type { IncomingMessage } from "node:http";
|
|
71
79
|
|
|
@@ -97,26 +105,36 @@ An `AuthVerifier` function validates the token and extracts its payload. The def
|
|
|
97
105
|
|
|
98
106
|
### Create a custom verifier
|
|
99
107
|
|
|
100
|
-
```
|
|
101
|
-
import {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
```ts docs-check
|
|
109
|
+
import {
|
|
110
|
+
CreateAuthDecorator,
|
|
111
|
+
AuthVerifier,
|
|
112
|
+
ValidateRaw,
|
|
113
|
+
} from "@antelopejs/interface-auth";
|
|
114
|
+
|
|
115
|
+
const userVerifier: AuthVerifier<{ userId: string }> = async (
|
|
116
|
+
data,
|
|
117
|
+
options,
|
|
118
|
+
) => {
|
|
119
|
+
const payload = await ValidateRaw<unknown>(data, options);
|
|
120
|
+
if (
|
|
121
|
+
typeof payload !== "object" ||
|
|
122
|
+
payload === null ||
|
|
123
|
+
!("userId" in payload) ||
|
|
124
|
+
typeof payload.userId !== "string"
|
|
125
|
+
) {
|
|
126
|
+
throw new Error("Invalid user payload");
|
|
112
127
|
}
|
|
128
|
+
return { userId: payload.userId };
|
|
113
129
|
};
|
|
114
130
|
|
|
115
|
-
const
|
|
116
|
-
authenticator:
|
|
131
|
+
const UserAuth = CreateAuthDecorator({
|
|
132
|
+
authenticator: userVerifier,
|
|
117
133
|
});
|
|
118
134
|
```
|
|
119
135
|
|
|
136
|
+
A verifier must establish trust in the token before returning its payload. Decoding Base64 or parsing JSON alone does not authenticate a request. The generic argument to `ValidateRaw<T>` describes the expected result for TypeScript; it does not validate the payload's shape.
|
|
137
|
+
|
|
120
138
|
The `AuthVerifier` type signature is:
|
|
121
139
|
|
|
122
140
|
```typescript
|
|
@@ -153,9 +171,7 @@ const AdminOnly = CreateAuthDecorator({
|
|
|
153
171
|
The `AuthValidator` type signature is:
|
|
154
172
|
|
|
155
173
|
```typescript
|
|
156
|
-
type AuthValidator<T = unknown, R = unknown> = (
|
|
157
|
-
data: T,
|
|
158
|
-
) => Promise<R> | R;
|
|
174
|
+
type AuthValidator<T = unknown, R = unknown> = (data: T) => Promise<R> | R;
|
|
159
175
|
```
|
|
160
176
|
|
|
161
177
|
## Authentication pipeline
|
package/docs/3.token-handling.md
CHANGED
|
@@ -21,10 +21,10 @@ console.log(token); // Signed token string
|
|
|
21
21
|
|
|
22
22
|
The function accepts two arguments:
|
|
23
23
|
|
|
24
|
-
| Argument | Type
|
|
25
|
-
| --------- |
|
|
26
|
-
| `data` | `string \| Buffer \| object`
|
|
27
|
-
| `options` | `SignOptions` (optional)
|
|
24
|
+
| Argument | Type | Description |
|
|
25
|
+
| --------- | ---------------------------- | ----------------------------- |
|
|
26
|
+
| `data` | `string \| Buffer \| object` | The data to sign |
|
|
27
|
+
| `options` | `SignOptions` (optional) | Signing configuration options |
|
|
28
28
|
|
|
29
29
|
`SignRaw` returns a `Promise<string>` that resolves to the signed token.
|
|
30
30
|
|
|
@@ -32,10 +32,10 @@ The function accepts two arguments:
|
|
|
32
32
|
|
|
33
33
|
The `SignOptions` interface configures token generation.
|
|
34
34
|
|
|
35
|
-
| Property | Type | Description
|
|
36
|
-
| ----------- | ------------------ |
|
|
35
|
+
| Property | Type | Description |
|
|
36
|
+
| ----------- | ------------------ | ---------------------------------------------------------------------------- |
|
|
37
37
|
| `expiresIn` | `string \| number` | Token expiration time as seconds or a timespan string (e.g., `"1h"`, `"2d"`) |
|
|
38
|
-
| `notBefore` | `string \| number` | Duration before which the token is not valid
|
|
38
|
+
| `notBefore` | `string \| number` | Duration before which the token is not valid |
|
|
39
39
|
|
|
40
40
|
### `SignServerResponse`
|
|
41
41
|
|
|
@@ -59,28 +59,30 @@ async function login(res: ServerResponse) {
|
|
|
59
59
|
|
|
60
60
|
The function accepts four arguments:
|
|
61
61
|
|
|
62
|
-
| Argument | Type
|
|
63
|
-
| --------------- |
|
|
64
|
-
| `res` | `ServerResponse`
|
|
65
|
-
| `data` | `string \| Buffer \| object` | The data to sign
|
|
66
|
-
| `signOptions` | `SignOptions` (optional)
|
|
67
|
-
| `cookieOptions` | `CookieOptions` (optional) | Cookie configuration options
|
|
62
|
+
| Argument | Type | Description |
|
|
63
|
+
| --------------- | ---------------------------- | ----------------------------- |
|
|
64
|
+
| `res` | `ServerResponse` | The HTTP response object |
|
|
65
|
+
| `data` | `string \| Buffer \| object` | The data to sign |
|
|
66
|
+
| `signOptions` | `SignOptions` (optional) | Signing configuration options |
|
|
67
|
+
| `cookieOptions` | `CookieOptions` (optional) | Cookie configuration options |
|
|
68
68
|
|
|
69
|
-
The cookie is set with the name `ANTELOPEJS_AUTH` and the signed token as its value. The function returns a `Promise<ServerResponse>` that resolves to the same response object once the
|
|
69
|
+
The cookie is set with the name `ANTELOPEJS_AUTH` and the signed token as its value. The function replaces the response's existing `Set-Cookie` header and returns a `Promise<ServerResponse>` that resolves to the same response object once the header has been set. It does not send or end the response.
|
|
70
70
|
|
|
71
71
|
### `CookieOptions`
|
|
72
72
|
|
|
73
|
-
The `CookieOptions` interface
|
|
73
|
+
The `CookieOptions` interface supplies attributes to the authentication cookie. The current serializer writes keys literally, omits `false` and `undefined`, writes `true` as a standalone directive, and converts other values with `String(value)`.
|
|
74
74
|
|
|
75
|
-
| Property | Type | Description
|
|
76
|
-
| ---------- | --------- |
|
|
77
|
-
| `maxAge` | `number` |
|
|
78
|
-
| `signed` | `boolean` |
|
|
79
|
-
| `expires` | `Date` |
|
|
80
|
-
| `httpOnly` | `boolean` | Prevents client-side JavaScript from accessing the cookie
|
|
81
|
-
| `path` | `string` | URL path for which the cookie is valid
|
|
82
|
-
| `domain` | `string` | Domain for which the cookie is valid
|
|
83
|
-
| `secure` | `boolean` | Only sends the cookie over HTTPS
|
|
75
|
+
| Property | Type | Description |
|
|
76
|
+
| ---------- | --------- | ------------------------------------------------------------------------------- |
|
|
77
|
+
| `maxAge` | `number` | Written as `maxAge=<number>`; not converted to the standard `Max-Age` attribute |
|
|
78
|
+
| `signed` | `boolean` | Written as a directive when true; does not add a cookie signature |
|
|
79
|
+
| `expires` | `Date` | Written using `String(date)`, not an explicit HTTP-date formatter |
|
|
80
|
+
| `httpOnly` | `boolean` | Prevents client-side JavaScript from accessing the cookie |
|
|
81
|
+
| `path` | `string` | URL path for which the cookie is valid |
|
|
82
|
+
| `domain` | `string` | Domain for which the cookie is valid |
|
|
83
|
+
| `secure` | `boolean` | Only sends the cookie over HTTPS |
|
|
84
|
+
|
|
85
|
+
Do not rely on `maxAge`, `signed`, or `expires` for browser lifetime or extra signing guarantees in this implementation. Use a standards-compliant cookie serializer when those features are required, and keep token expiration in `SignOptions`. No cookie attributes are added by default.
|
|
84
86
|
|
|
85
87
|
## Token validation
|
|
86
88
|
|
|
@@ -101,9 +103,9 @@ try {
|
|
|
101
103
|
|
|
102
104
|
The function accepts two arguments:
|
|
103
105
|
|
|
104
|
-
| Argument | Type
|
|
105
|
-
| --------- |
|
|
106
|
-
| `token` | `string` (optional)
|
|
106
|
+
| Argument | Type | Description |
|
|
107
|
+
| --------- | -------------------------- | -------------------------- |
|
|
108
|
+
| `token` | `string` (optional) | The signed token to verify |
|
|
107
109
|
| `options` | `VerifyOptions` (optional) | Verification configuration |
|
|
108
110
|
|
|
109
111
|
### `VerifyOptions`
|
|
@@ -112,8 +114,8 @@ The `VerifyOptions` interface configures token validation.
|
|
|
112
114
|
|
|
113
115
|
| Property | Type | Description |
|
|
114
116
|
| ------------------ | ------------------ | ---------------------------------------------------- |
|
|
115
|
-
| `ignoreExpiration` | `boolean` | If `true`, expired tokens are still considered valid
|
|
116
|
-
| `ignoreNotBefore` | `boolean` | If `true`, tokens not yet valid are accepted
|
|
117
|
+
| `ignoreExpiration` | `boolean` | If `true`, expired tokens are still considered valid |
|
|
118
|
+
| `ignoreNotBefore` | `boolean` | If `true`, tokens not yet valid are accepted |
|
|
117
119
|
| `maxAge` | `string \| number` | Maximum allowed age of the token |
|
|
118
120
|
|
|
119
121
|
### Example with verify options
|
|
@@ -4,7 +4,7 @@ The Interface Auth provides decorators for integrating authentication into API c
|
|
|
4
4
|
|
|
5
5
|
## The `@Authentication` decorator
|
|
6
6
|
|
|
7
|
-
The `@Authentication` decorator retrieves and validates a token from the
|
|
7
|
+
The `@Authentication` decorator retrieves and validates a token from `x-antelopejs-auth`, or from the `ANTELOPEJS_AUTH` cookie when the header is absent, and injects the verified payload into the parameter.
|
|
8
8
|
|
|
9
9
|
```typescript
|
|
10
10
|
import { Controller, Get } from "@antelopejs/interface-api";
|
|
@@ -81,14 +81,16 @@ export const ApiKeyAuth = CreateAuthDecorator({
|
|
|
81
81
|
|
|
82
82
|
The function accepts an object with the following properties:
|
|
83
83
|
|
|
84
|
-
| Property | Type | Description
|
|
85
|
-
| ---------------------- | --------------------- |
|
|
84
|
+
| Property | Type | Description |
|
|
85
|
+
| ---------------------- | --------------------- | --------------------------------------------------------------- |
|
|
86
86
|
| `source` | `AuthSource` | Extracts the token from the request (defaults to header/cookie) |
|
|
87
|
-
| `authenticator` | `AuthVerifier<T>` | Verifies the token and returns the payload
|
|
88
|
-
| `authenticatorOptions` | `VerifyOptions` | Options passed to the authenticator
|
|
89
|
-
| `validator` | `AuthValidator<T, R>` | Validates and transforms the authenticated data
|
|
87
|
+
| `authenticator` | `AuthVerifier<T>` | Verifies the token and returns the payload |
|
|
88
|
+
| `authenticatorOptions` | `VerifyOptions` | Options passed to the authenticator |
|
|
89
|
+
| `validator` | `AuthValidator<T, R>` | Validates and transforms the authenticated data |
|
|
90
90
|
|
|
91
|
-
All properties are optional.
|
|
91
|
+
All properties are optional. The default source reads the header/cookie, the default authenticator calls `ValidateRaw`, and the default verification options are `{}`. Without a validator, the verified payload is passed through unchanged.
|
|
92
|
+
|
|
93
|
+
A validator passed to a decorator call replaces the configured validator; the two do not compose. Return a transformed value to inject it, or throw to deny access. Returning `false` or `null` does not reject the request. A custom authenticator that accepts a missing token also permits it unless a validator throws.
|
|
92
94
|
|
|
93
95
|
## Class-level authentication
|
|
94
96
|
|
|
@@ -165,8 +167,8 @@ class UserController extends Controller("/users") {
|
|
|
165
167
|
|
|
166
168
|
The `@Authentication` decorator (and any custom decorator created with `CreateAuthDecorator`) can be applied at three levels:
|
|
167
169
|
|
|
168
|
-
| Scope
|
|
169
|
-
|
|
|
170
|
-
| Parameter
|
|
171
|
-
| Property
|
|
172
|
-
| Class
|
|
170
|
+
| Scope | Effect |
|
|
171
|
+
| --------- | --------------------------------------------------------------------- |
|
|
172
|
+
| Parameter | Injects the verified payload into a single handler parameter |
|
|
173
|
+
| Property | Populates a class property with the verified payload for all handlers |
|
|
174
|
+
| Class | Requires authentication for every route in the controller |
|
package/package.json
CHANGED
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antelopejs/interface-auth",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "AntelopeJS interface for
|
|
3
|
+
"version": "0.0.7",
|
|
4
|
+
"description": "AntelopeJS interface for token authentication: sign and verify tokens and inject the verified payload into API handlers",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"antelopejs",
|
|
7
|
-
"interface",
|
|
8
7
|
"auth",
|
|
9
|
-
"
|
|
8
|
+
"authentication",
|
|
9
|
+
"interface",
|
|
10
|
+
"jwt",
|
|
11
|
+
"token"
|
|
10
12
|
],
|
|
13
|
+
"homepage": "https://interfaces.antelopejs.com/docs/auth",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/AntelopeJS/interface-auth/issues"
|
|
16
|
+
},
|
|
17
|
+
"license": "Apache-2.0",
|
|
11
18
|
"repository": {
|
|
12
19
|
"type": "git",
|
|
13
20
|
"url": "git+https://github.com/AntelopeJS/interface-auth.git"
|
|
14
21
|
},
|
|
15
|
-
"license": "Apache-2.0",
|
|
16
|
-
"packageManager": "pnpm@10.6.5",
|
|
17
|
-
"main": "dist/index.js",
|
|
18
|
-
"types": "dist/index.d.ts",
|
|
19
22
|
"files": [
|
|
20
23
|
"dist",
|
|
21
24
|
"docs",
|
|
22
25
|
"skills"
|
|
23
26
|
],
|
|
27
|
+
"main": "dist/index.js",
|
|
28
|
+
"types": "dist/index.d.ts",
|
|
24
29
|
"exports": {
|
|
25
30
|
".": {
|
|
26
31
|
"types": "./dist/index.d.ts",
|
|
@@ -28,37 +33,47 @@
|
|
|
28
33
|
},
|
|
29
34
|
"./package.json": "./package.json"
|
|
30
35
|
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public",
|
|
38
|
+
"provenance": true
|
|
39
|
+
},
|
|
31
40
|
"scripts": {
|
|
32
41
|
"build": "rimraf dist && tsc",
|
|
33
|
-
"format": "
|
|
34
|
-
"lint:fix": "
|
|
35
|
-
"lint": "
|
|
42
|
+
"format": "oxfmt .",
|
|
43
|
+
"lint:fix": "oxlint --fix",
|
|
44
|
+
"lint": "oxlint",
|
|
36
45
|
"prepack": "pnpm run build",
|
|
37
46
|
"release": "pnpm run lint && pnpm run prepack && release-it",
|
|
38
|
-
"test": "pnpm run build && ajs module test ."
|
|
47
|
+
"test": "pnpm run build && ajs module test .",
|
|
48
|
+
"format:check": "oxfmt --check .",
|
|
49
|
+
"knip": "knip"
|
|
39
50
|
},
|
|
40
51
|
"devDependencies": {
|
|
41
|
-
"@antelopejs/
|
|
42
|
-
"@antelopejs/interface-
|
|
43
|
-
"@
|
|
52
|
+
"@antelopejs/core": "^1.16.0",
|
|
53
|
+
"@antelopejs/interface-api": "^0.0.15",
|
|
54
|
+
"@antelopejs/interface-core": "^0.2.4",
|
|
55
|
+
"@antelopejs/tooling-configs": "^0.0.9",
|
|
44
56
|
"@types/chai": "^4.3.20",
|
|
45
57
|
"@types/mocha": "^10.0.10",
|
|
46
58
|
"@types/node": "^22.19.15",
|
|
47
59
|
"@types/semver": "^7.7.1",
|
|
48
60
|
"chai": "^4.5.0",
|
|
61
|
+
"eslint-plugin-perfectionist": "^5.11.0",
|
|
62
|
+
"knip": "^6.34.0",
|
|
49
63
|
"mongodb-memory-server-core": "^10.4.3",
|
|
64
|
+
"oxfmt": "^0.66.0",
|
|
65
|
+
"oxlint": "1.81.0",
|
|
66
|
+
"oxlint-tsgolint": "^7.0.2001",
|
|
50
67
|
"release-it": "^19.2.4",
|
|
51
68
|
"release-it-changelogen": "^0.1.0",
|
|
52
69
|
"rimraf": "^6.1.3",
|
|
53
70
|
"typescript": "^5.9.3"
|
|
54
71
|
},
|
|
55
72
|
"peerDependencies": {
|
|
56
|
-
"@antelopejs/interface-api": ">=0.0.
|
|
57
|
-
"@antelopejs/interface-core": ">=0.
|
|
58
|
-
},
|
|
59
|
-
"publishConfig": {
|
|
60
|
-
"access": "public"
|
|
73
|
+
"@antelopejs/interface-api": ">=0.0.15 <1.0.0",
|
|
74
|
+
"@antelopejs/interface-core": ">=0.2.4 <1.0.0"
|
|
61
75
|
},
|
|
76
|
+
"packageManager": "pnpm@10.6.5",
|
|
62
77
|
"antelopeJs": {
|
|
63
78
|
"test": "src/antelope.test.ts",
|
|
64
79
|
"skills": [
|
|
@@ -18,11 +18,18 @@ All symbols come from the package root (the exports map exposes no other code su
|
|
|
18
18
|
|
|
19
19
|
```ts
|
|
20
20
|
import {
|
|
21
|
-
Authentication,
|
|
22
|
-
|
|
21
|
+
Authentication,
|
|
22
|
+
CreateAuthDecorator,
|
|
23
|
+
SignRaw,
|
|
24
|
+
ValidateRaw,
|
|
25
|
+
SignServerResponse,
|
|
23
26
|
internal, // provider side only
|
|
24
|
-
type AuthSource,
|
|
25
|
-
type
|
|
27
|
+
type AuthSource,
|
|
28
|
+
type AuthVerifier,
|
|
29
|
+
type AuthValidator,
|
|
30
|
+
type SignOptions,
|
|
31
|
+
type VerifyOptions,
|
|
32
|
+
type CookieOptions,
|
|
26
33
|
} from "@antelopejs/interface-auth";
|
|
27
34
|
```
|
|
28
35
|
|
|
@@ -34,7 +41,10 @@ import {
|
|
|
34
41
|
import { Controller, Get, Post } from "@antelopejs/interface-api";
|
|
35
42
|
import { Authentication, SignRaw } from "@antelopejs/interface-auth";
|
|
36
43
|
|
|
37
|
-
interface LibrarianSession {
|
|
44
|
+
interface LibrarianSession {
|
|
45
|
+
id: string;
|
|
46
|
+
branch: string;
|
|
47
|
+
}
|
|
38
48
|
|
|
39
49
|
class LibrarianController extends Controller("/librarians") {
|
|
40
50
|
@Post("login")
|
|
@@ -63,7 +73,7 @@ import { internal } from "@antelopejs/interface-auth";
|
|
|
63
73
|
|
|
64
74
|
ImplementInterface(internal, {
|
|
65
75
|
Verify: (token, options) => decodeAndVerify(token, options), // return payload, throw on invalid
|
|
66
|
-
Sign: (data, options) => signToken(data, options),
|
|
76
|
+
Sign: (data, options) => signToken(data, options), // return token string
|
|
67
77
|
});
|
|
68
78
|
```
|
|
69
79
|
|