@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/tests/index.test.ts"],"names":[],"mappings":";;AAAA,+BAA8B;
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/tests/index.test.ts"],"names":[],"mappings":";;AAAA,+BAA8B;AAC9B,6DAAuD;AACvD,0BAA0C;AAc1C,MAAM,SAAS,GAAc;IAC3B,OAAO,EAAE;QACP,IAAI,EAAE,KAAK;QACX,KAAK,EAAE,eAAe;QACtB,QAAQ,EAAE,uBAAuB;KAClC;IACD,SAAS,EAAE;QACT,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,iBAAiB;QACxB,QAAQ,EAAE,uBAAuB;KAClC;CACF,CAAC;AAEF,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,oBAAoB,EAAE,KAAK,IAAI,EAAE;QAClC,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC;QACnC,MAAM,KAAK,GAAG,MAAM,IAAA,WAAO,EAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE3D,MAAM,YAAY,GAAG,MAAM,IAAA,eAAW,EAAC,KAAK,CAAC,CAAC;QAE9C,IAAA,aAAM,EAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAA,aAAM,EAAC,YAAY,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7D,IAAA,aAAM,EAAC,YAAY,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC/D,IAAA,aAAM,EAAC,YAAY,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;QACpC,MAAM,YAAY,GAAG,mBAAmB,CAAC;QAEzC,IAAI,CAAC;YACH,MAAM,IAAA,eAAW,EAAC,YAAY,CAAC,CAAC;YAChC,aAAM,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;QAC/D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAA,aAAM,EAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,0BAAU,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;QACpC,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC;QACnC,MAAM,KAAK,GAAG,MAAM,IAAA,WAAO,EAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;QAE5D,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;QAExD,IAAI,CAAC;YACH,MAAM,IAAA,eAAW,EAAC,KAAK,CAAC,CAAC;YACzB,aAAM,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;QAC/D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAA,aAAM,EAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,0BAAU,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const chai_1 = require("chai");
|
|
4
|
+
const node_http_1 = require("node:http");
|
|
5
|
+
const node_net_1 = require("node:net");
|
|
6
|
+
const interface_core_1 = require("@antelopejs/interface-core");
|
|
7
|
+
const __1 = require("..");
|
|
8
|
+
const signedToken = "signed-token";
|
|
9
|
+
const signCalls = [];
|
|
10
|
+
const verifyCalls = [];
|
|
11
|
+
let verifyOutcome;
|
|
12
|
+
function requestWith(headers) {
|
|
13
|
+
const request = new node_http_1.IncomingMessage(new node_net_1.Socket());
|
|
14
|
+
Object.assign(request.headers, headers);
|
|
15
|
+
return request;
|
|
16
|
+
}
|
|
17
|
+
function newResponse() {
|
|
18
|
+
return new node_http_1.ServerResponse(new node_http_1.IncomingMessage(new node_net_1.Socket()));
|
|
19
|
+
}
|
|
20
|
+
function resetProviderState() {
|
|
21
|
+
signCalls.length = 0;
|
|
22
|
+
verifyCalls.length = 0;
|
|
23
|
+
verifyOutcome = () => ({});
|
|
24
|
+
}
|
|
25
|
+
function implementProviders() {
|
|
26
|
+
(0, interface_core_1.ImplementInterface)({ Sign: __1.internal.Sign, Verify: __1.internal.Verify }, {
|
|
27
|
+
Sign: async (...args) => {
|
|
28
|
+
signCalls.push(args);
|
|
29
|
+
return signedToken;
|
|
30
|
+
},
|
|
31
|
+
Verify: async (...args) => {
|
|
32
|
+
verifyCalls.push(args);
|
|
33
|
+
return verifyOutcome();
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
describe("Auth interface built from this repository", () => {
|
|
38
|
+
before(implementProviders);
|
|
39
|
+
beforeEach(resetProviderState);
|
|
40
|
+
it("SignRaw hands the payload and options to the Sign provider", async () => {
|
|
41
|
+
const token = await (0, __1.SignRaw)({ userId: "u1" }, { expiresIn: "1h" });
|
|
42
|
+
(0, chai_1.expect)(token).to.equal(signedToken);
|
|
43
|
+
(0, chai_1.expect)(signCalls).to.deep.equal([[{ userId: "u1" }, { expiresIn: "1h" }]]);
|
|
44
|
+
});
|
|
45
|
+
it("ValidateRaw returns the payload of the Verify provider", async () => {
|
|
46
|
+
verifyOutcome = () => ({ name: "Bob" });
|
|
47
|
+
const payload = await (0, __1.ValidateRaw)("the-token", { maxAge: "1h" });
|
|
48
|
+
(0, chai_1.expect)(payload).to.deep.equal({ name: "Bob" });
|
|
49
|
+
(0, chai_1.expect)(verifyCalls).to.deep.equal([["the-token", { maxAge: "1h" }]]);
|
|
50
|
+
});
|
|
51
|
+
it("ValidateRaw rejects with the error of the Verify provider", async () => {
|
|
52
|
+
const failure = new Error("rejected by the provider");
|
|
53
|
+
verifyOutcome = () => {
|
|
54
|
+
throw failure;
|
|
55
|
+
};
|
|
56
|
+
let caught;
|
|
57
|
+
try {
|
|
58
|
+
await (0, __1.ValidateRaw)("bad-token");
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
caught = error;
|
|
62
|
+
}
|
|
63
|
+
(0, chai_1.expect)(caught).to.equal(failure);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe("Auth helpers built from this repository", () => {
|
|
67
|
+
before(implementProviders);
|
|
68
|
+
beforeEach(resetProviderState);
|
|
69
|
+
it("set-cookie uses standalone boolean directives", async () => {
|
|
70
|
+
const response = newResponse();
|
|
71
|
+
await (0, __1.SignServerResponse)(response, { userId: "user-7" }, { expiresIn: "1h" }, { httpOnly: true });
|
|
72
|
+
const setCookieHeader = response.getHeader("set-cookie");
|
|
73
|
+
(0, chai_1.expect)(setCookieHeader).to.be.a("string");
|
|
74
|
+
(0, chai_1.expect)(setCookieHeader).to.match(/^ANTELOPEJS_AUTH=/);
|
|
75
|
+
(0, chai_1.expect)(setCookieHeader).to.match(/httpOnly/);
|
|
76
|
+
(0, chai_1.expect)(setCookieHeader).to.not.match(/httpOnly=true/);
|
|
77
|
+
});
|
|
78
|
+
it("SignServerResponse serializes cookie attributes literally and omits false ones", async () => {
|
|
79
|
+
const bare = newResponse();
|
|
80
|
+
const attributed = newResponse();
|
|
81
|
+
await (0, __1.SignServerResponse)(bare, { userId: "u1" });
|
|
82
|
+
await (0, __1.SignServerResponse)(attributed, { userId: "u1" }, undefined, {
|
|
83
|
+
path: "/",
|
|
84
|
+
maxAge: 60,
|
|
85
|
+
secure: true,
|
|
86
|
+
httpOnly: false,
|
|
87
|
+
});
|
|
88
|
+
(0, chai_1.expect)(bare.getHeader("set-cookie")).to.equal(`ANTELOPEJS_AUTH=${signedToken}`);
|
|
89
|
+
(0, chai_1.expect)(attributed.getHeader("set-cookie")).to.equal(`ANTELOPEJS_AUTH=${signedToken}; path=/; maxAge=60; secure`);
|
|
90
|
+
});
|
|
91
|
+
it("defaultSource reads the header first and the cookie otherwise", () => {
|
|
92
|
+
const response = newResponse();
|
|
93
|
+
const headerAndCookie = requestWith({
|
|
94
|
+
"x-antelopejs-auth": "from-header",
|
|
95
|
+
cookie: "ANTELOPEJS_AUTH=from-cookie",
|
|
96
|
+
});
|
|
97
|
+
const cookieOnly = requestWith({
|
|
98
|
+
cookie: "other=1; ANTELOPEJS_AUTH=from-cookie; more=2",
|
|
99
|
+
});
|
|
100
|
+
(0, chai_1.expect)(__1.internal.defaultSource(headerAndCookie, response)).to.equal("from-header");
|
|
101
|
+
(0, chai_1.expect)(__1.internal.defaultSource(cookieOnly, response)).to.equal("from-cookie");
|
|
102
|
+
(0, chai_1.expect)(__1.internal.defaultSource(requestWith({}), response)).to.equal(undefined);
|
|
103
|
+
});
|
|
104
|
+
it("CheckAuthentication verifies through the Verify provider and applies the validator", async () => {
|
|
105
|
+
verifyOutcome = () => ({ id: 1 });
|
|
106
|
+
const request = requestWith({ "x-antelopejs-auth": "the-token" });
|
|
107
|
+
const callbacks = {
|
|
108
|
+
source: __1.internal.defaultSource,
|
|
109
|
+
authenticator: __1.ValidateRaw,
|
|
110
|
+
authenticatorOptions: {},
|
|
111
|
+
validator: undefined,
|
|
112
|
+
};
|
|
113
|
+
const plain = await __1.internal.CheckAuthentication(request, newResponse(), callbacks);
|
|
114
|
+
const validated = await __1.internal.CheckAuthentication(request, newResponse(), {
|
|
115
|
+
...callbacks,
|
|
116
|
+
validator: (claims) => ({ claims, validated: true }),
|
|
117
|
+
});
|
|
118
|
+
(0, chai_1.expect)(plain).to.deep.equal({ id: 1 });
|
|
119
|
+
(0, chai_1.expect)(validated).to.deep.equal({ claims: { id: 1 }, validated: true });
|
|
120
|
+
(0, chai_1.expect)(verifyCalls).to.deep.equal([
|
|
121
|
+
["the-token", {}],
|
|
122
|
+
["the-token", {}],
|
|
123
|
+
]);
|
|
124
|
+
});
|
|
125
|
+
it("CheckAuthentication calls the callbacks without the callbacks object as receiver", async () => {
|
|
126
|
+
const receivers = [];
|
|
127
|
+
const callbacks = {
|
|
128
|
+
source() {
|
|
129
|
+
receivers.push(this);
|
|
130
|
+
return "the-token";
|
|
131
|
+
},
|
|
132
|
+
authenticator() {
|
|
133
|
+
receivers.push(this);
|
|
134
|
+
return { id: 1 };
|
|
135
|
+
},
|
|
136
|
+
authenticatorOptions: {},
|
|
137
|
+
validator() {
|
|
138
|
+
receivers.push(this);
|
|
139
|
+
return "validated";
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
const result = await __1.internal.CheckAuthentication(requestWith({}), newResponse(), callbacks);
|
|
143
|
+
(0, chai_1.expect)(result).to.equal("validated");
|
|
144
|
+
(0, chai_1.expect)(receivers).to.deep.equal([undefined, undefined, undefined]);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
//# sourceMappingURL=local-build.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-build.test.js","sourceRoot":"","sources":["../../src/tests/local-build.test.ts"],"names":[],"mappings":"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"}
|
package/docs/1.introduction.md
CHANGED
|
@@ -1,27 +1,67 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: Authenticate API requests
|
|
3
|
+
description: Install the auth interface, protect a first endpoint with a verified token, and pick where to plug in your own source, verifier, or validator.
|
|
4
|
+
mode: how-to
|
|
5
|
+
---
|
|
2
6
|
|
|
3
7
|
## Overview
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
Use `@antelopejs/interface-auth` to sign tokens and inject verified payloads into API handlers. Your application still owns credential checks, payload validation, and permission rules. A valid signature alone does not grant access to a resource.
|
|
6
10
|
|
|
7
|
-
This interface depends on the [
|
|
11
|
+
This interface depends on the [interface-api](https://github.com/AntelopeJS/interface-api) package, which provides the decorators that inject parameters.
|
|
8
12
|
|
|
9
13
|
## Core concepts
|
|
10
14
|
|
|
11
|
-
The
|
|
15
|
+
The interface has three layers:
|
|
12
16
|
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
17
|
+
- Token handling. `SignRaw`, `ValidateRaw`, and `SignServerResponse` sign and verify tokens.
|
|
18
|
+
- Authentication decorators. The `@Authentication` decorator and the `CreateAuthDecorator` function inject verified payloads into handler parameters.
|
|
19
|
+
- A pipeline you can change. Custom sources, verifiers, and validators replace each step of the flow.
|
|
16
20
|
|
|
17
21
|
## Installation
|
|
18
22
|
|
|
19
23
|
```bash
|
|
20
|
-
|
|
24
|
+
pnpm add @antelopejs/interface-auth
|
|
21
25
|
```
|
|
22
26
|
|
|
27
|
+
## Protect an endpoint
|
|
28
|
+
|
|
29
|
+
Start with a running AntelopeJS API module and an authentication module that implements this interface. Installing the package does not configure signing keys or attach a token implementation.
|
|
30
|
+
|
|
31
|
+
This controller requires a verified token for `GET /account`. It returns no claims, so you can check that your provider and transport work before you add payload validation.
|
|
32
|
+
|
|
33
|
+
```ts docs-check
|
|
34
|
+
import { Controller, Get } from "@antelopejs/interface-api";
|
|
35
|
+
import { Authentication } from "@antelopejs/interface-auth";
|
|
36
|
+
|
|
37
|
+
@Authentication()
|
|
38
|
+
class AccountController extends Controller("/account") {
|
|
39
|
+
@Get("")
|
|
40
|
+
status() {
|
|
41
|
+
return { authenticated: true };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Send an issued token in `x-antelopejs-auth` to receive `{ "authenticated": true }`. A missing or invalid token must fail verification before the handler runs. This route checks authentication only, not permission to read another user's account.
|
|
47
|
+
|
|
48
|
+
1. **Issue a token after you check the credentials.** Use [token handling](./3.token-handling.md) to choose `SignRaw` or `SignServerResponse` and set an expiry.
|
|
49
|
+
2. **Choose one transport.** The default source reads a raw token from `x-antelopejs-auth`, then tries `ANTELOPEJS_AUTH` only when the header is absent. For `Authorization: Bearer`, use the [custom source example](./2.authentication.md#create-a-custom-source).
|
|
50
|
+
3. **Require authentication.** Add [a parameter, property, or class decorator](./4.parameter-decoration.md) to the controller.
|
|
51
|
+
4. **Enforce your policy.** Validate the payload shape, and throw when the caller lacks permission. A validator that returns `false` injects `false`. It does not deny access.
|
|
52
|
+
|
|
53
|
+
## Choose where to customize
|
|
54
|
+
|
|
55
|
+
| You need to change | Customize | Keep this boundary |
|
|
56
|
+
| -------------------------- | --------------- | -------------------------------------------- |
|
|
57
|
+
| Where the token comes from | `source` | Extraction does not establish trust. |
|
|
58
|
+
| How the token is verified | `authenticator` | Verify before you return a payload. |
|
|
59
|
+
| Who may use the endpoint | `validator` | Throw to reject. Return the value to inject. |
|
|
60
|
+
|
|
61
|
+
Before you expose the route, test a missing token, an invalid token, and a valid token without the required permission, as well as the successful request. See [authentication and authorization](./2.authentication.md) for the complete pipeline.
|
|
62
|
+
|
|
23
63
|
## Documentation sections
|
|
24
64
|
|
|
25
|
-
- [Authentication
|
|
26
|
-
- [Token
|
|
27
|
-
- [
|
|
65
|
+
- [Authentication and authorization](./2.authentication.md) covers the flow, sources, verifiers, and validators.
|
|
66
|
+
- [Token handling](./3.token-handling.md) covers the functions that sign and verify tokens.
|
|
67
|
+
- [Require authentication in controllers](./4.parameter-decoration.md) covers the decorators and custom decorators.
|
package/docs/2.authentication.md
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: Authentication and authorization
|
|
3
|
+
description: How the auth interface turns a request into an injected payload, through a source, an authenticator, and an optional validator, and which part of the policy stays in your application.
|
|
4
|
+
mode: explanation
|
|
5
|
+
---
|
|
2
6
|
|
|
3
|
-
Authentication
|
|
7
|
+
Authentication establishes trust in a token. Authorization decides what its holder may do. This interface connects token verification to API parameter injection. Your application supplies credential checks, payload validation, and access rules.
|
|
4
8
|
|
|
5
9
|
## Authentication flow
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
An authentication flow has four steps:
|
|
8
12
|
|
|
9
|
-
1.
|
|
10
|
-
2.
|
|
11
|
-
3.
|
|
12
|
-
4.
|
|
13
|
+
1. Token generation. `SignRaw` or `SignServerResponse` signs user data into a token.
|
|
14
|
+
2. Token transport. The client sends the token in the chosen header or cookie. You choose the client's storage and CSRF protection. This interface configures neither.
|
|
15
|
+
3. Token validation. The server verifies the token on each request.
|
|
16
|
+
4. Authorization. Your code checks whether the authenticated user may access the requested resource.
|
|
13
17
|
|
|
14
18
|
### Example authentication flow
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
The persistence functions in this example, `validateUserCredentials` and `getUserProfile`, belong to your application. The profile route verifies a token. A validator would add the payload shape and resource permissions. For production cookies, you also decide the Secure, SameSite, expiry, and CSRF policy of your deployment.
|
|
21
|
+
|
|
22
|
+
```typescript fragment
|
|
17
23
|
import { SignRaw, Authentication } from "@antelopejs/interface-auth";
|
|
18
24
|
import {
|
|
19
25
|
Controller,
|
|
@@ -43,7 +49,7 @@ class UserController extends Controller("/users") {
|
|
|
43
49
|
|
|
44
50
|
result.addHeader(
|
|
45
51
|
"Set-Cookie",
|
|
46
|
-
`ANTELOPEJS_AUTH=${token}; HttpOnly; Path=/`,
|
|
52
|
+
`ANTELOPEJS_AUTH=${token}; HttpOnly; Secure; SameSite=Lax; Path=/`,
|
|
47
53
|
);
|
|
48
54
|
|
|
49
55
|
return result;
|
|
@@ -53,21 +59,23 @@ class UserController extends Controller("/users") {
|
|
|
53
59
|
async getProfile(
|
|
54
60
|
@Authentication() userData: { userId: number; role: string },
|
|
55
61
|
) {
|
|
56
|
-
//
|
|
57
|
-
//
|
|
62
|
+
// Step 3: the token is verified. Resource authorization is application policy.
|
|
63
|
+
// An invalid token rejects the request before this code runs.
|
|
58
64
|
return { user: await getUserProfile(userData.userId) };
|
|
59
65
|
}
|
|
60
66
|
}
|
|
61
67
|
```
|
|
62
68
|
|
|
69
|
+
This cookie example requires HTTPS. `SameSite=Lax` is a starting policy for same-site browser use. It does not replace a decision on CSRF protection or cross-site requirements. The helpers named above are application code, not a complete login implementation.
|
|
70
|
+
|
|
63
71
|
## Authentication sources
|
|
64
72
|
|
|
65
73
|
An `AuthSource` function extracts the authentication token from the incoming HTTP request. The default source checks two locations in order:
|
|
66
74
|
|
|
67
|
-
1.
|
|
68
|
-
2.
|
|
75
|
+
1. The `x-antelopejs-auth` header.
|
|
76
|
+
2. The `ANTELOPEJS_AUTH` cookie.
|
|
69
77
|
|
|
70
|
-
The header contains the raw token, not `Bearer <token>`. A present header takes precedence even when it is empty or invalid
|
|
78
|
+
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
79
|
|
|
72
80
|
### Create a custom source
|
|
73
81
|
|
|
@@ -93,6 +101,8 @@ const BearerAuth = CreateAuthDecorator({
|
|
|
93
101
|
The `AuthSource` type signature is:
|
|
94
102
|
|
|
95
103
|
```typescript
|
|
104
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
105
|
+
|
|
96
106
|
type AuthSource = (
|
|
97
107
|
req: IncomingMessage,
|
|
98
108
|
res: ServerResponse,
|
|
@@ -101,7 +111,7 @@ type AuthSource = (
|
|
|
101
111
|
|
|
102
112
|
## Authentication verifiers
|
|
103
113
|
|
|
104
|
-
An `AuthVerifier` function validates the token and extracts its payload. The default verifier
|
|
114
|
+
An `AuthVerifier` function validates the token and extracts its payload. The default verifier is `ValidateRaw`, which calls the module that implements this interface, such as `@antelopejs/auth-jwt` for JSON Web Tokens.
|
|
105
115
|
|
|
106
116
|
### Create a custom verifier
|
|
107
117
|
|
|
@@ -116,13 +126,8 @@ const userVerifier: AuthVerifier<{ userId: string }> = async (
|
|
|
116
126
|
data,
|
|
117
127
|
options,
|
|
118
128
|
) => {
|
|
119
|
-
const payload = await ValidateRaw
|
|
120
|
-
if (
|
|
121
|
-
typeof payload !== "object" ||
|
|
122
|
-
payload === null ||
|
|
123
|
-
!("userId" in payload) ||
|
|
124
|
-
typeof payload.userId !== "string"
|
|
125
|
-
) {
|
|
129
|
+
const payload = await ValidateRaw(data, options);
|
|
130
|
+
if (typeof payload === "string" || typeof payload.userId !== "string") {
|
|
126
131
|
throw new Error("Invalid user payload");
|
|
127
132
|
}
|
|
128
133
|
return { userId: payload.userId };
|
|
@@ -133,12 +138,14 @@ const UserAuth = CreateAuthDecorator({
|
|
|
133
138
|
});
|
|
134
139
|
```
|
|
135
140
|
|
|
136
|
-
A verifier must establish trust in the token before
|
|
141
|
+
A verifier must establish trust in the token before it returns the payload. Decoding Base64 or parsing JSON alone does not authenticate a request. `ValidateRaw` returns an `AuthClaims`, which is `string | JsonObject`. The interface does not know the shape of what you signed, so reading a field needs a check like the one above. A configured validator receives the verifier's return type as its input.
|
|
137
142
|
|
|
138
143
|
The `AuthVerifier` type signature is:
|
|
139
144
|
|
|
140
145
|
```typescript
|
|
141
|
-
type
|
|
146
|
+
import type { AuthClaims, VerifyOptions } from "@antelopejs/interface-auth";
|
|
147
|
+
|
|
148
|
+
type AuthVerifier<T = AuthClaims> = (
|
|
142
149
|
data?: string,
|
|
143
150
|
options?: VerifyOptions,
|
|
144
151
|
) => Promise<T> | T;
|
|
@@ -146,21 +153,16 @@ type AuthVerifier<T = unknown> = (
|
|
|
146
153
|
|
|
147
154
|
## Authentication validators
|
|
148
155
|
|
|
149
|
-
An `AuthValidator` function
|
|
156
|
+
An `AuthValidator` function runs extra checks on the verified data. Validators run after the verifier. A validator can transform the result, or throw an error to reject the request.
|
|
150
157
|
|
|
151
158
|
```typescript
|
|
152
159
|
import { CreateAuthDecorator, AuthValidator } from "@antelopejs/interface-auth";
|
|
153
160
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
role: string;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const adminValidator: AuthValidator<UserPayload, UserPayload> = (userData) => {
|
|
160
|
-
if (!userData || userData.role !== "admin") {
|
|
161
|
+
const adminValidator: AuthValidator = (claims) => {
|
|
162
|
+
if (typeof claims === "string" || claims.role !== "admin") {
|
|
161
163
|
throw new Error("Admin access required");
|
|
162
164
|
}
|
|
163
|
-
return
|
|
165
|
+
return claims;
|
|
164
166
|
};
|
|
165
167
|
|
|
166
168
|
const AdminOnly = CreateAuthDecorator({
|
|
@@ -171,15 +173,25 @@ const AdminOnly = CreateAuthDecorator({
|
|
|
171
173
|
The `AuthValidator` type signature is:
|
|
172
174
|
|
|
173
175
|
```typescript
|
|
174
|
-
type
|
|
176
|
+
import type { AuthClaims } from "@antelopejs/interface-auth";
|
|
177
|
+
|
|
178
|
+
type AuthValidator<T = AuthClaims, R = unknown> = (data: T) => Promise<R> | R;
|
|
175
179
|
```
|
|
176
180
|
|
|
181
|
+
Without an `authenticator`, a validator receives the `AuthClaims` the default verifier returns. When you also configure an `authenticator`, the validator receives whatever that authenticator returns, so a typed verifier such as `userVerifier` above gives the validator a typed value.
|
|
182
|
+
|
|
177
183
|
## Authentication pipeline
|
|
178
184
|
|
|
179
|
-
The
|
|
185
|
+
The pipeline takes the request through three stages:
|
|
180
186
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
187
|
+
{width="480"}
|
|
188
|
+
|
|
189
|
+
An omitted `source` or `authenticator` callback uses the default. There is no default policy validator. Without one, the decorator injects the verified payload unchanged.
|
|
190
|
+
|
|
191
|
+
| Stage | Input | Output | Failure boundary |
|
|
192
|
+
| --------------- | ------------------------------ | -------------------- | -------------------------------------------------------------- |
|
|
193
|
+
| `source` | Request and response | Token or `undefined` | Missing input still reaches the authenticator. |
|
|
194
|
+
| `authenticator` | Token and verification options | Verified payload | A thrown error or rejected promise stops processing. |
|
|
195
|
+
| `validator` | Verified payload | Value to inject | Throw to deny access. A falsy return value is not a rejection. |
|
|
184
196
|
|
|
185
|
-
|
|
197
|
+
A validator passed to a decorator call replaces the configured validator. It does not run after it as an extra check. To compose validators, keep the shared policy in a function that each validator calls.
|
package/docs/3.token-handling.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: Token handling
|
|
3
|
+
description: Reference for SignRaw, SignServerResponse, and ValidateRaw, with their options, argument types, return values, and cookie serialization limits.
|
|
4
|
+
mode: reference
|
|
5
|
+
---
|
|
2
6
|
|
|
3
|
-
|
|
7
|
+
`@antelopejs/interface-auth` exports three functions that sign and verify tokens. The decorators call `ValidateRaw` by default.
|
|
4
8
|
|
|
5
9
|
## Token generation
|
|
6
10
|
|
|
@@ -16,15 +20,17 @@ const token = await SignRaw(
|
|
|
16
20
|
{ expiresIn: "1h" },
|
|
17
21
|
);
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
// Return the token through your chosen authentication transport.
|
|
20
24
|
```
|
|
21
25
|
|
|
22
26
|
The function accepts two arguments:
|
|
23
27
|
|
|
24
|
-
| Argument | Type
|
|
25
|
-
| --------- |
|
|
26
|
-
| `data` | `string \| Buffer \|
|
|
27
|
-
| `options` | `SignOptions` (optional)
|
|
28
|
+
| Argument | Type | Description |
|
|
29
|
+
| --------- | -------------------------------- | ----------------------------- |
|
|
30
|
+
| `data` | `string \| Buffer \| JsonObject` | The data to sign |
|
|
31
|
+
| `options` | `SignOptions` (optional) | Signing configuration options |
|
|
32
|
+
|
|
33
|
+
`JsonObject` maps string keys to JSON values: `string`, `number`, `boolean`, `null`, arrays, and nested objects. A `Date`, a class instance, or a function is a compile error. Convert it first, for example with `date.toISOString()`. A key whose value is `undefined` is accepted, and serialization drops it. An object typed with an `interface` has no index signature and is not assignable. Declare it with a `type` alias, or spread it into a literal.
|
|
28
34
|
|
|
29
35
|
`SignRaw` returns a `Promise<string>` that resolves to the signed token.
|
|
30
36
|
|
|
@@ -32,10 +38,12 @@ The function accepts two arguments:
|
|
|
32
38
|
|
|
33
39
|
The `SignOptions` interface configures token generation.
|
|
34
40
|
|
|
35
|
-
| Property | Type
|
|
36
|
-
| ----------- |
|
|
37
|
-
| `expiresIn` | `
|
|
38
|
-
| `notBefore` | `
|
|
41
|
+
| Property | Type | Description |
|
|
42
|
+
| ----------- | -------------------- | ------------------------------------------------------------------------------- |
|
|
43
|
+
| `expiresIn` | `number \| TimeSpan` | Token expiration time as seconds or a timespan string, such as `"1h"` or `"2d"` |
|
|
44
|
+
| `notBefore` | `number \| TimeSpan` | Duration before which the token is not valid |
|
|
45
|
+
|
|
46
|
+
`TimeSpan` is the timespan grammar of the `ms` package. It is a number followed by an optional unit in any case, with or without a space, such as `"90"`, `"2h"`, or `"7 days"`. A bare number string counts milliseconds. A string outside this grammar, such as `"soon"`, does not compile.
|
|
39
47
|
|
|
40
48
|
### `SignServerResponse`
|
|
41
49
|
|
|
@@ -59,30 +67,32 @@ async function login(res: ServerResponse) {
|
|
|
59
67
|
|
|
60
68
|
The function accepts four arguments:
|
|
61
69
|
|
|
62
|
-
| Argument | Type
|
|
63
|
-
| --------------- |
|
|
64
|
-
| `res` | `ServerResponse`
|
|
65
|
-
| `data` | `string \| Buffer \|
|
|
66
|
-
| `signOptions` | `SignOptions` (optional)
|
|
67
|
-
| `cookieOptions` | `CookieOptions` (optional)
|
|
70
|
+
| Argument | Type | Description |
|
|
71
|
+
| --------------- | -------------------------------- | ----------------------------- |
|
|
72
|
+
| `res` | `ServerResponse` | The HTTP response object |
|
|
73
|
+
| `data` | `string \| Buffer \| JsonObject` | The data to sign |
|
|
74
|
+
| `signOptions` | `SignOptions` (optional) | Signing configuration options |
|
|
75
|
+
| `cookieOptions` | `CookieOptions` (optional) | Cookie configuration options |
|
|
68
76
|
|
|
69
77
|
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
78
|
|
|
71
79
|
### `CookieOptions`
|
|
72
80
|
|
|
73
|
-
The `CookieOptions` interface supplies attributes to the authentication cookie. The
|
|
81
|
+
The `CookieOptions` interface supplies attributes to the authentication cookie. The serializer writes keys literally and omits `false` and `undefined` values. It writes `true` as a standalone directive and converts other values with `String(value)`.
|
|
74
82
|
|
|
75
|
-
| Property | Type | Description
|
|
76
|
-
| ---------- | --------- |
|
|
77
|
-
| `maxAge` | `number` | Written as `maxAge=<number
|
|
78
|
-
| `signed` | `boolean` | Written as a directive when true
|
|
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
|
|
83
|
+
| Property | Type | Description |
|
|
84
|
+
| ---------- | --------- | --------------------------------------------------------------------- |
|
|
85
|
+
| `maxAge` | `number` | Written as `maxAge=<number>`, not as the standard `Max-Age` attribute |
|
|
86
|
+
| `signed` | `boolean` | Written as a directive when true. It does not add a cookie signature. |
|
|
87
|
+
| `expires` | `Date` | Written using `String(date)`, not an explicit HTTP-date formatter |
|
|
88
|
+
| `httpOnly` | `boolean` | Prevents client-side JavaScript from accessing the cookie |
|
|
89
|
+
| `path` | `string` | URL path for which the cookie is valid |
|
|
90
|
+
| `domain` | `string` | Domain for which the cookie is valid |
|
|
91
|
+
| `secure` | `boolean` | Only sends the cookie over HTTPS |
|
|
84
92
|
|
|
85
|
-
|
|
93
|
+
`maxAge`, `signed`, and `expires` do not set the browser lifetime or add a signature. When you need those features, use a standards-compliant cookie serializer, and keep token expiration in `SignOptions`. The function adds no cookie attributes by default.
|
|
94
|
+
|
|
95
|
+
`CookieOptions` has no `sameSite` field. If your deployment requires SameSite, serialize the cookie yourself and set the response header, as in the [authentication flow](./2.authentication.md#example-authentication-flow). Do not cast unsupported options into this type.
|
|
86
96
|
|
|
87
97
|
## Token validation
|
|
88
98
|
|
|
@@ -93,11 +103,16 @@ The `ValidateRaw` function verifies a token and returns the data contained withi
|
|
|
93
103
|
```typescript
|
|
94
104
|
import { ValidateRaw } from "@antelopejs/interface-auth";
|
|
95
105
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
106
|
+
async function inspect(token: string) {
|
|
107
|
+
try {
|
|
108
|
+
const claims = await ValidateRaw(token);
|
|
109
|
+
console.log(claims); // { userId: 123, role: "admin", iat: ..., exp: ... } with auth-jwt
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.error(
|
|
112
|
+
"Invalid token:",
|
|
113
|
+
error instanceof Error ? error.message : String(error),
|
|
114
|
+
);
|
|
115
|
+
}
|
|
101
116
|
}
|
|
102
117
|
```
|
|
103
118
|
|
|
@@ -108,6 +123,10 @@ The function accepts two arguments:
|
|
|
108
123
|
| `token` | `string` (optional) | The signed token to verify |
|
|
109
124
|
| `options` | `VerifyOptions` (optional) | Verification configuration |
|
|
110
125
|
|
|
126
|
+
`ValidateRaw` returns a `Promise<AuthClaims>`, where `AuthClaims` is `string | JsonObject`. The value is the signed string, or the JSON object that was signed. `ValidateRaw` has no type parameter. Read a field only after you check it, or pass the result to a parser of your own. A [custom verifier](./2.authentication.md#create-a-custom-verifier) does that once for every route.
|
|
127
|
+
|
|
128
|
+
The promise rejects when the token is missing or fails verification. The rejection value comes from the implementation and is not always an `Error`. `@antelopejs/auth-jwt` rejects with an `HTTPResult`: status 401 for a missing token and 403 for an invalid or expired one. The example above handles both kinds of value.
|
|
129
|
+
|
|
111
130
|
### `VerifyOptions`
|
|
112
131
|
|
|
113
132
|
The `VerifyOptions` interface configures token validation.
|
|
@@ -123,9 +142,12 @@ The `VerifyOptions` interface configures token validation.
|
|
|
123
142
|
```typescript
|
|
124
143
|
import { ValidateRaw } from "@antelopejs/interface-auth";
|
|
125
144
|
|
|
126
|
-
//
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
});
|
|
145
|
+
// Limit token age without bypassing expiration or not-before checks.
|
|
146
|
+
async function verifyRecent(token: string) {
|
|
147
|
+
return ValidateRaw(token, {
|
|
148
|
+
maxAge: "30m",
|
|
149
|
+
});
|
|
150
|
+
}
|
|
131
151
|
```
|
|
152
|
+
|
|
153
|
+
Leave `ignoreExpiration` and `ignoreNotBefore` unset for normal authentication. They bypass the time checks. Set them only when a separate, explicit policy accepts such tokens. A successful `ValidateRaw` call verifies the token through your provider. It does not check the shape of the payload.
|