@ontrails/permits 1.0.0-beta.13 → 1.0.0-beta.14
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/.turbo/turbo-lint.log +1 -1
- package/CHANGELOG.md +11 -0
- package/README.md +175 -0
- package/dist/auth-gate.d.ts +18 -0
- package/dist/auth-gate.d.ts.map +1 -0
- package/dist/auth-gate.js +56 -0
- package/dist/auth-gate.js.map +1 -0
- package/dist/auth-provision.d.ts +11 -0
- package/dist/auth-provision.d.ts.map +1 -0
- package/dist/auth-provision.js +22 -0
- package/dist/auth-provision.js.map +1 -0
- package/dist/connectors/connector.d.ts +26 -0
- package/dist/connectors/connector.d.ts.map +1 -0
- package/dist/connectors/connector.js +2 -0
- package/dist/connectors/connector.js.map +1 -0
- package/dist/connectors/jwt.d.ts +25 -0
- package/dist/connectors/jwt.d.ts.map +1 -0
- package/dist/connectors/jwt.js +148 -0
- package/dist/connectors/jwt.js.map +1 -0
- package/dist/extraction.d.ts +6 -6
- package/dist/extraction.d.ts.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/permit.d.ts +2 -2
- package/dist/permit.js +2 -2
- package/dist/trails/auth-verify.d.ts +3 -3
- package/dist/trails/auth-verify.d.ts.map +1 -1
- package/dist/trails/auth-verify.js +31 -31
- package/dist/trails/auth-verify.js.map +1 -1
- package/package.json +2 -2
- package/tsconfig.tsbuildinfo +1 -1
package/.turbo/turbo-lint.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @ontrails/permits
|
|
2
2
|
|
|
3
|
+
## 1.0.0-beta.14
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 69057e9: Add hierarchical CLI command trees and structured input, enforce established-only topo exports across trailheads, move developer topo and tracker state onto shared `trails.db` with pins and maintenance flows, and ship schema-derived stores through `@ontrails/store` and its Drizzle runtime.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [69057e9]
|
|
12
|
+
- @ontrails/core@1.0.0-beta.14
|
|
13
|
+
|
|
3
14
|
## 1.0.0-beta.13
|
|
4
15
|
|
|
5
16
|
### Minor Changes
|
package/README.md
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# @ontrails/permits
|
|
2
|
+
|
|
3
|
+
Scope-based authorization for Trails.
|
|
4
|
+
|
|
5
|
+
The permits package owns the connector-agnostic `authProvision` and `authGate`. Connector packages bind those declarations to concrete auth logic, just like a trailhead connector binds a topo to CLI, MCP, or HTTP.
|
|
6
|
+
|
|
7
|
+
## The core pattern
|
|
8
|
+
|
|
9
|
+
### 1. Declare permit requirements on trails
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
export const create = trail('gist.create', {
|
|
13
|
+
permit: { scopes: ['gist:write'] },
|
|
14
|
+
blaze: async (input, ctx) => {
|
|
15
|
+
// authGate enforces scopes before blaze runs
|
|
16
|
+
return Result.ok(newGist);
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export const search = trail('gist.search', {
|
|
21
|
+
permit: 'public',
|
|
22
|
+
blaze: async (input, ctx) => {
|
|
23
|
+
// No authentication required
|
|
24
|
+
return Result.ok(results);
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Register the auth gate
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { authGate } from '@ontrails/permits';
|
|
33
|
+
|
|
34
|
+
export const app = topo('my-app', gistModule);
|
|
35
|
+
// Register authGate with your trailhead
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The gate reads each trail's `permit` field:
|
|
39
|
+
|
|
40
|
+
- `'public'` or `undefined` — gate passes through
|
|
41
|
+
- `{ scopes: [...] }` — gate checks that `ctx.permit` contains all required scopes
|
|
42
|
+
|
|
43
|
+
### 3. Bind a connector at bootstrap
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { createJwtConnector } from '@ontrails/permits/jwt';
|
|
47
|
+
|
|
48
|
+
const connector = createJwtConnector({
|
|
49
|
+
secret: process.env.JWT_SECRET,
|
|
50
|
+
issuer: 'https://auth.example.com',
|
|
51
|
+
audience: 'api.example.com',
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Auth connectors
|
|
56
|
+
|
|
57
|
+
An auth connector authenticates requests and produces permits.
|
|
58
|
+
|
|
59
|
+
### Built-in: JWT connector
|
|
60
|
+
|
|
61
|
+
Verifies HS256-signed JWTs and extracts claims into permits:
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { createJwtConnector } from '@ontrails/permits/jwt';
|
|
65
|
+
|
|
66
|
+
const connector = createJwtConnector({
|
|
67
|
+
secret: 'your-hmac-secret',
|
|
68
|
+
issuer: 'https://auth.example.com',
|
|
69
|
+
audience: 'api.example.com',
|
|
70
|
+
scopesClaim: 'scope',
|
|
71
|
+
rolesClaim: 'roles',
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Custom connectors
|
|
76
|
+
|
|
77
|
+
Implement the `AuthConnector` interface:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import type { AuthConnector, PermitExtractionInput, Permit } from '@ontrails/permits';
|
|
81
|
+
|
|
82
|
+
const myConnector: AuthConnector = {
|
|
83
|
+
authenticate: async (input: PermitExtractionInput) => {
|
|
84
|
+
if (!input.bearerToken) return Result.ok(null);
|
|
85
|
+
const permit: Permit = {
|
|
86
|
+
id: 'user-42',
|
|
87
|
+
scopes: ['user:read', 'user:write'],
|
|
88
|
+
roles: ['admin'],
|
|
89
|
+
};
|
|
90
|
+
return Result.ok(permit);
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Permits and scopes
|
|
96
|
+
|
|
97
|
+
A `Permit` is the resolved identity and scopes from successful authentication:
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
interface Permit {
|
|
101
|
+
readonly id: string;
|
|
102
|
+
readonly scopes: readonly string[];
|
|
103
|
+
readonly roles?: readonly string[];
|
|
104
|
+
readonly tenantId?: string;
|
|
105
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Access the permit in your blaze:
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { getPermit } from '@ontrails/permits';
|
|
113
|
+
|
|
114
|
+
const myTrail = trail('do.something', {
|
|
115
|
+
blaze: async (_input, ctx) => {
|
|
116
|
+
const permit = getPermit(ctx);
|
|
117
|
+
if (!permit) return Result.err(new Error('Not authenticated'));
|
|
118
|
+
return Result.ok({ userId: permit.id });
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Scopes follow the `entity:action` convention: `user:read`, `gist:write`, etc.
|
|
124
|
+
|
|
125
|
+
## The auth.verify trail
|
|
126
|
+
|
|
127
|
+
An infrastructure trail that verifies bearer tokens and returns permits:
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
import { authVerify } from '@ontrails/permits';
|
|
131
|
+
|
|
132
|
+
// Returns { valid: true, permit: { id, scopes, roles } }
|
|
133
|
+
// or { valid: false, error: 'Token has expired', errorCode: 'expired_token' }
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Testing with mock permits
|
|
137
|
+
|
|
138
|
+
Use `mintTestPermit()` and `mintPermitForTrail()` in tests:
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import { mintTestPermit, mintPermitForTrail } from '@ontrails/permits';
|
|
142
|
+
|
|
143
|
+
const permit = mintTestPermit({
|
|
144
|
+
id: 'user-123',
|
|
145
|
+
scopes: ['gist:read', 'gist:write'],
|
|
146
|
+
roles: ['editor'],
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Mint a permit matching a trail's requirements
|
|
150
|
+
const trailPermit = mintPermitForTrail(myTrail);
|
|
151
|
+
// { id: 'test-...', scopes: ['gist:write'] }
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Permit governance
|
|
155
|
+
|
|
156
|
+
Use `validatePermits()` to check trails against governance rules:
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
import { validatePermits } from '@ontrails/permits';
|
|
160
|
+
|
|
161
|
+
const diagnostics = validatePermits(app.list());
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Built-in rules:
|
|
165
|
+
|
|
166
|
+
- `destroyWithoutPermit` — error if a destroy trail has no permit
|
|
167
|
+
- `writeWithoutPermit` — warning if a write trail has no permit
|
|
168
|
+
- `scopeNamingConsistency` — warning if a scope doesn't follow `entity:action`
|
|
169
|
+
- `orphanScopeDetection` — warning if a scope appears in only one trail
|
|
170
|
+
|
|
171
|
+
## Installation
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
bun add @ontrails/permits @ontrails/core zod
|
|
175
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Gate } from '@ontrails/core';
|
|
2
|
+
/**
|
|
3
|
+
* A {@link Gate} that enforces permit scopes declared on trails.
|
|
4
|
+
*
|
|
5
|
+
* The gate reads the trail's `permit` field (a `PermitRequirement`):
|
|
6
|
+
*
|
|
7
|
+
* - If `permit` is `'public'` or `undefined` the gate passes through.
|
|
8
|
+
* - If `permit` has `scopes`, the gate checks that `ctx.permit` contains
|
|
9
|
+
* all required scopes. A superset is fine; missing scopes produce a
|
|
10
|
+
* `PermitError`.
|
|
11
|
+
*
|
|
12
|
+
* Because `ctx.cross()` re-enters `executeTrail` (which applies gates),
|
|
13
|
+
* this gate automatically re-checks on every invocation in a crossing chain.
|
|
14
|
+
* No special crossing-chain handling is needed — it is built into the
|
|
15
|
+
* architecture.
|
|
16
|
+
*/
|
|
17
|
+
export declare const authGate: Gate;
|
|
18
|
+
//# sourceMappingURL=auth-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-gate.d.ts","sourceRoot":"","sources":["../src/auth-gate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AA6B3C;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,QAAQ,EAAE,IAkCtB,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Result } from '@ontrails/core';
|
|
2
|
+
import { PermitError } from './errors.js';
|
|
3
|
+
import { getPermit } from './permit.js';
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Helpers (defined before callers — no use-before-define)
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
/**
|
|
8
|
+
* Returns `true` when the permit requirement means "no enforcement needed."
|
|
9
|
+
* Either the trail hasn't declared a permit posture or has explicitly
|
|
10
|
+
* opted out with `'public'`.
|
|
11
|
+
*/
|
|
12
|
+
const isPassThrough = (requirement) => requirement === undefined || requirement === 'public';
|
|
13
|
+
/** Returns scopes present in `required` but absent from `held`. */
|
|
14
|
+
const findMissing = (required, held) => required.filter((s) => !held.includes(s));
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Auth gate
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
/**
|
|
19
|
+
* A {@link Gate} that enforces permit scopes declared on trails.
|
|
20
|
+
*
|
|
21
|
+
* The gate reads the trail's `permit` field (a `PermitRequirement`):
|
|
22
|
+
*
|
|
23
|
+
* - If `permit` is `'public'` or `undefined` the gate passes through.
|
|
24
|
+
* - If `permit` has `scopes`, the gate checks that `ctx.permit` contains
|
|
25
|
+
* all required scopes. A superset is fine; missing scopes produce a
|
|
26
|
+
* `PermitError`.
|
|
27
|
+
*
|
|
28
|
+
* Because `ctx.cross()` re-enters `executeTrail` (which applies gates),
|
|
29
|
+
* this gate automatically re-checks on every invocation in a crossing chain.
|
|
30
|
+
* No special crossing-chain handling is needed — it is built into the
|
|
31
|
+
* architecture.
|
|
32
|
+
*/
|
|
33
|
+
export const authGate = {
|
|
34
|
+
description: 'Enforces permit scopes declared on trails',
|
|
35
|
+
name: 'auth',
|
|
36
|
+
wrap: (_trail, impl) => {
|
|
37
|
+
const requirement = _trail.permit;
|
|
38
|
+
if (isPassThrough(requirement)) {
|
|
39
|
+
return impl;
|
|
40
|
+
}
|
|
41
|
+
return (input, ctx) => {
|
|
42
|
+
const permit = getPermit(ctx);
|
|
43
|
+
if (!permit) {
|
|
44
|
+
return Promise.resolve(Result.err(new PermitError('No permit provided')));
|
|
45
|
+
}
|
|
46
|
+
const missing = findMissing(requirement.scopes, permit.scopes);
|
|
47
|
+
if (missing.length > 0) {
|
|
48
|
+
return Promise.resolve(Result.err(new PermitError(`Missing scopes: ${missing.join(', ')}`, {
|
|
49
|
+
context: { missing, required: requirement.scopes },
|
|
50
|
+
})));
|
|
51
|
+
}
|
|
52
|
+
return Promise.resolve(impl(input, ctx));
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=auth-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-gate.js","sourceRoot":"","sources":["../src/auth-gate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAGxC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,8EAA8E;AAC9E,0DAA0D;AAC1D,8EAA8E;AAE9E;;;;GAIG;AACH,MAAM,aAAa,GAAG,CACpB,WAAoB,EACiB,EAAE,CACvC,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,QAAQ,CAAC;AAExD,mEAAmE;AACnE,MAAM,WAAW,GAAG,CAClB,QAA2B,EAC3B,IAAuB,EACJ,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAElE,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAS;IAC5B,WAAW,EAAE,2CAA2C;IACxD,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;QACrB,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC;QAElC,IAAI,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YACpB,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;YAE9B,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAO,OAAO,CAAC,OAAO,CACpB,MAAM,CAAC,GAAG,CAAC,IAAI,WAAW,CAAC,oBAAoB,CAAC,CAAC,CAClD,CAAC;YACJ,CAAC;YAED,MAAM,OAAO,GAAG,WAAW,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YAE/D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,OAAO,OAAO,CAAC,OAAO,CACpB,MAAM,CAAC,GAAG,CACR,IAAI,WAAW,CAAC,mBAAmB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE;oBACvD,OAAO,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE;iBACnD,CAAC,CACH,CACF,CAAC;YACJ,CAAC;YAED,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;QAC3C,CAAC,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AuthConnector } from './connectors/connector.js';
|
|
2
|
+
/**
|
|
3
|
+
* Auth provision — manages the auth connector lifecycle.
|
|
4
|
+
*
|
|
5
|
+
* The v1 factory returns a no-op connector that always succeeds (null permit).
|
|
6
|
+
* Real connector configuration will come through `ProvisionSpec.config`
|
|
7
|
+
* (TRL-91). The mock factory provides a synthetic connector that always
|
|
8
|
+
* succeeds.
|
|
9
|
+
*/
|
|
10
|
+
export declare const authProvision: import("@ontrails/core").Provision<AuthConnector>;
|
|
11
|
+
//# sourceMappingURL=auth-provision.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-provision.d.ts","sourceRoot":"","sources":["../src/auth-provision.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,mDAaxB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Result, provision } from '@ontrails/core';
|
|
2
|
+
/**
|
|
3
|
+
* Auth provision — manages the auth connector lifecycle.
|
|
4
|
+
*
|
|
5
|
+
* The v1 factory returns a no-op connector that always succeeds (null permit).
|
|
6
|
+
* Real connector configuration will come through `ProvisionSpec.config`
|
|
7
|
+
* (TRL-91). The mock factory provides a synthetic connector that always
|
|
8
|
+
* succeeds.
|
|
9
|
+
*/
|
|
10
|
+
export const authProvision = provision('auth', {
|
|
11
|
+
create: (_svc) => Result.ok({
|
|
12
|
+
// oxlint-disable-next-line require-await -- stub connector satisfies async interface
|
|
13
|
+
authenticate: async () => Result.ok(null),
|
|
14
|
+
}),
|
|
15
|
+
description: 'Authentication connector',
|
|
16
|
+
meta: { category: 'infrastructure' },
|
|
17
|
+
mock: () => ({
|
|
18
|
+
// oxlint-disable-next-line require-await -- mock connector satisfies async interface
|
|
19
|
+
authenticate: async () => Result.ok(null),
|
|
20
|
+
}),
|
|
21
|
+
});
|
|
22
|
+
//# sourceMappingURL=auth-provision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-provision.js","sourceRoot":"","sources":["../src/auth-provision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAInD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,SAAS,CAAgB,MAAM,EAAE;IAC5D,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CACf,MAAM,CAAC,EAAE,CAAC;QACR,qFAAqF;QACrF,YAAY,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC;KAClB,CAAC;IAC5B,WAAW,EAAE,0BAA0B;IACvC,IAAI,EAAE,EAAE,QAAQ,EAAE,gBAAgB,EAAE;IACpC,IAAI,EAAE,GAAG,EAAE,CACT,CAAC;QACC,qFAAqF;QACrF,YAAY,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC;KAC1C,CAAyB;CAC7B,CAAC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Result } from '@ontrails/core';
|
|
2
|
+
import type { PermitExtractionInput } from '../extraction.js';
|
|
3
|
+
import type { Permit } from '../permit.js';
|
|
4
|
+
/**
|
|
5
|
+
* @deprecated Use {@link PermitExtractionInput} instead. Kept as an alias
|
|
6
|
+
* for backward compatibility during migration.
|
|
7
|
+
*/
|
|
8
|
+
export type AuthCredentials = PermitExtractionInput;
|
|
9
|
+
/** Errors from auth connectors. */
|
|
10
|
+
export interface AuthError {
|
|
11
|
+
readonly code: 'expired_token' | 'insufficient_scope' | 'invalid_token' | 'missing_credentials';
|
|
12
|
+
readonly message: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Auth connector port. Given extraction input, produce a permit or an error.
|
|
16
|
+
*
|
|
17
|
+
* The connector receives the full {@link PermitExtractionInput} — trailhead,
|
|
18
|
+
* headers, requestId, and credential fields — so it can make richer
|
|
19
|
+
* decisions (e.g., rate-limit by trailhead or correlate via requestId).
|
|
20
|
+
*
|
|
21
|
+
* Deliberately narrow — no session management, no token refresh.
|
|
22
|
+
*/
|
|
23
|
+
export interface AuthConnector {
|
|
24
|
+
readonly authenticate: (input: PermitExtractionInput) => Promise<Result<Permit | null, AuthError>>;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=connector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connector.d.ts","sourceRoot":"","sources":["../../src/connectors/connector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,qBAAqB,CAAC;AAEpD,mCAAmC;AACnC,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EACT,eAAe,GACf,oBAAoB,GACpB,eAAe,GACf,qBAAqB,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,YAAY,EAAE,CACrB,KAAK,EAAE,qBAAqB,KACzB,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;CAChD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connector.js","sourceRoot":"","sources":["../../src/connectors/connector.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { AuthConnector } from './connector.js';
|
|
2
|
+
/** Configuration for the JWT auth connector. */
|
|
3
|
+
export interface JwtConnectorOptions {
|
|
4
|
+
/** HMAC secret for HS256 verification. */
|
|
5
|
+
readonly secret?: string;
|
|
6
|
+
/** JWKS endpoint for RS256/ES256 (not yet implemented). */
|
|
7
|
+
readonly jwksUrl?: string;
|
|
8
|
+
/** Expected issuer claim. */
|
|
9
|
+
readonly issuer?: string;
|
|
10
|
+
/** Expected audience claim. */
|
|
11
|
+
readonly audience?: string;
|
|
12
|
+
/** Claim containing scopes (default: 'scope'). */
|
|
13
|
+
readonly scopesClaim?: string;
|
|
14
|
+
/** Claim containing roles (default: 'roles'). */
|
|
15
|
+
readonly rolesClaim?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create a JWT auth connector using Bun's native crypto.
|
|
19
|
+
*
|
|
20
|
+
* Verifies HS256-signed JWTs, extracts claims into a Permit, and checks
|
|
21
|
+
* issuer/audience when configured. Returns `Result.ok(null)` when no
|
|
22
|
+
* credentials are provided.
|
|
23
|
+
*/
|
|
24
|
+
export declare const createJwtConnector: (options: JwtConnectorOptions) => AuthConnector;
|
|
25
|
+
//# sourceMappingURL=jwt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/connectors/jwt.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,gBAAgB,CAAC;AAI/D,gDAAgD;AAChD,MAAM,WAAW,mBAAmB;IAClC,0CAA0C;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,6BAA6B;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,kDAAkD;IAClD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,iDAAiD;IACjD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AA2LD;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAC7B,SAAS,mBAAmB,KAC3B,aAeF,CAAC"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { Result } from '@ontrails/core';
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Helpers (defined before callers)
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
const authErr = (code, message) => Result.err({ code, message });
|
|
6
|
+
/** Base64url-decode a string to bytes. */
|
|
7
|
+
const base64urlDecode = (input) => {
|
|
8
|
+
const padded = input
|
|
9
|
+
.replaceAll('-', '+')
|
|
10
|
+
.replaceAll('_', '/')
|
|
11
|
+
.padEnd(input.length + ((4 - (input.length % 4)) % 4), '=');
|
|
12
|
+
const binary = atob(padded);
|
|
13
|
+
const bytes = new Uint8Array(binary.length);
|
|
14
|
+
for (let i = 0; i < binary.length; i += 1) {
|
|
15
|
+
bytes[i] = binary.codePointAt(i) ?? 0;
|
|
16
|
+
}
|
|
17
|
+
return bytes;
|
|
18
|
+
};
|
|
19
|
+
/** Decode a JWT payload without verifying the signature. */
|
|
20
|
+
const decodePayload = (token) => {
|
|
21
|
+
const parts = token.split('.');
|
|
22
|
+
if (parts.length !== 3) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const json = new TextDecoder().decode(base64urlDecode(parts[1] ?? ''));
|
|
27
|
+
return JSON.parse(json);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
/** Import a secret as an HMAC CryptoKey. */
|
|
34
|
+
const importHmacKey = (secret) => {
|
|
35
|
+
const encoder = new TextEncoder();
|
|
36
|
+
return crypto.subtle.importKey('raw', encoder.encode(secret), { hash: 'SHA-256', name: 'HMAC' }, false, ['verify']);
|
|
37
|
+
};
|
|
38
|
+
/** Verify the HMAC-SHA256 signature of a JWT. */
|
|
39
|
+
const verifyHmacSignature = (token, key) => {
|
|
40
|
+
const lastDot = token.lastIndexOf('.');
|
|
41
|
+
if (lastDot === -1) {
|
|
42
|
+
return Promise.resolve(false);
|
|
43
|
+
}
|
|
44
|
+
const data = token.slice(0, lastDot);
|
|
45
|
+
const signature = base64urlDecode(token.slice(lastDot + 1));
|
|
46
|
+
const encoder = new TextEncoder();
|
|
47
|
+
return crypto.subtle.verify('HMAC', key, signature.buffer, encoder.encode(data));
|
|
48
|
+
};
|
|
49
|
+
/** Validate standard claims (exp, iss, aud). */
|
|
50
|
+
const validateClaims = (payload, options) => {
|
|
51
|
+
if (payload.exp !== undefined &&
|
|
52
|
+
payload.exp < Math.floor(Date.now() / 1000)) {
|
|
53
|
+
return { code: 'expired_token', message: 'Token has expired' };
|
|
54
|
+
}
|
|
55
|
+
if (options.issuer && payload.iss !== options.issuer) {
|
|
56
|
+
return { code: 'invalid_token', message: 'Issuer mismatch' };
|
|
57
|
+
}
|
|
58
|
+
if (options.audience) {
|
|
59
|
+
const { aud } = payload;
|
|
60
|
+
const matches = Array.isArray(aud)
|
|
61
|
+
? aud.includes(options.audience)
|
|
62
|
+
: aud === options.audience;
|
|
63
|
+
if (!matches) {
|
|
64
|
+
return { code: 'invalid_token', message: 'Audience mismatch' };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return undefined;
|
|
68
|
+
};
|
|
69
|
+
/** Extract scopes from a payload claim (space-separated string or array). */
|
|
70
|
+
const extractScopes = (payload, claim) => {
|
|
71
|
+
const raw = payload[claim];
|
|
72
|
+
if (typeof raw === 'string') {
|
|
73
|
+
return raw.split(' ').filter(Boolean);
|
|
74
|
+
}
|
|
75
|
+
if (Array.isArray(raw)) {
|
|
76
|
+
return raw.filter((s) => typeof s === 'string' && s.length > 0);
|
|
77
|
+
}
|
|
78
|
+
return [];
|
|
79
|
+
};
|
|
80
|
+
/** Extract roles from a payload claim (string array). */
|
|
81
|
+
const extractRoles = (payload, claim) => {
|
|
82
|
+
const raw = payload[claim];
|
|
83
|
+
if (!Array.isArray(raw)) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
return raw.filter((r) => typeof r === 'string');
|
|
87
|
+
};
|
|
88
|
+
/** Build a Permit from a validated JWT payload. */
|
|
89
|
+
const buildPermit = (payload, options) => {
|
|
90
|
+
if (!payload.sub) {
|
|
91
|
+
return authErr('invalid_token', 'Missing subject claim (sub)');
|
|
92
|
+
}
|
|
93
|
+
const roles = extractRoles(payload, options.rolesClaim ?? 'roles');
|
|
94
|
+
return Result.ok({
|
|
95
|
+
id: payload.sub,
|
|
96
|
+
scopes: extractScopes(payload, options.scopesClaim ?? 'scope'),
|
|
97
|
+
...(roles ? { roles } : {}),
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
/** Verify the signature and return the decoded payload, or an error. */
|
|
101
|
+
const decodeAndVerify = async (token, secret) => {
|
|
102
|
+
const payload = decodePayload(token);
|
|
103
|
+
if (!payload) {
|
|
104
|
+
return authErr('invalid_token', 'Malformed JWT');
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
const key = await importHmacKey(secret);
|
|
108
|
+
const valid = await verifyHmacSignature(token, key);
|
|
109
|
+
return valid
|
|
110
|
+
? Result.ok(payload)
|
|
111
|
+
: authErr('invalid_token', 'Invalid signature');
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return authErr('invalid_token', 'Malformed token signature');
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
/** Validate claims and build a permit from a verified payload. */
|
|
118
|
+
const payloadToPermit = (payload, options) => {
|
|
119
|
+
const claimError = validateClaims(payload, options);
|
|
120
|
+
if (claimError) {
|
|
121
|
+
return Result.err(claimError);
|
|
122
|
+
}
|
|
123
|
+
return buildPermit(payload, options);
|
|
124
|
+
};
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
// Factory
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
/**
|
|
129
|
+
* Create a JWT auth connector using Bun's native crypto.
|
|
130
|
+
*
|
|
131
|
+
* Verifies HS256-signed JWTs, extracts claims into a Permit, and checks
|
|
132
|
+
* issuer/audience when configured. Returns `Result.ok(null)` when no
|
|
133
|
+
* credentials are provided.
|
|
134
|
+
*/
|
|
135
|
+
export const createJwtConnector = (options) => {
|
|
136
|
+
const authenticate = async (input) => {
|
|
137
|
+
if (!input.bearerToken) {
|
|
138
|
+
return Result.ok(null);
|
|
139
|
+
}
|
|
140
|
+
if (!options.secret) {
|
|
141
|
+
return authErr('invalid_token', 'No secret configured');
|
|
142
|
+
}
|
|
143
|
+
const decoded = await decodeAndVerify(input.bearerToken, options.secret);
|
|
144
|
+
return decoded.isErr() ? decoded : payloadToPermit(decoded.value, options);
|
|
145
|
+
};
|
|
146
|
+
return { authenticate };
|
|
147
|
+
};
|
|
148
|
+
//# sourceMappingURL=jwt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../src/connectors/jwt.ts"],"names":[],"mappings":"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"}
|
package/dist/extraction.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Normalized input for auth
|
|
2
|
+
* Normalized input for auth connectors.
|
|
3
3
|
*
|
|
4
|
-
* Each
|
|
5
|
-
* them into this shape. No
|
|
4
|
+
* Each trailhead extracts raw credentials from its transport and normalizes
|
|
5
|
+
* them into this shape. No trailhead types (Request, McpSession, etc.) cross
|
|
6
6
|
* into core — only this interface.
|
|
7
7
|
*/
|
|
8
8
|
export interface PermitExtractionInput {
|
|
9
|
-
/** Which
|
|
10
|
-
readonly
|
|
9
|
+
/** Which trailhead produced this extraction */
|
|
10
|
+
readonly trailhead: 'http' | 'mcp' | 'cli';
|
|
11
11
|
/** Bearer token from Authorization header or equivalent */
|
|
12
12
|
readonly bearerToken?: string;
|
|
13
13
|
/** Session identifier from transport handshake */
|
|
14
14
|
readonly sessionId?: string;
|
|
15
|
-
/** Raw headers (HTTP
|
|
15
|
+
/** Raw headers (HTTP trailhead only, typically) */
|
|
16
16
|
readonly headers?: Headers;
|
|
17
17
|
/** Correlation ID for tracing */
|
|
18
18
|
readonly requestId: string;
|
package/dist/extraction.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extraction.d.ts","sourceRoot":"","sources":["../src/extraction.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC
|
|
1
|
+
{"version":3,"file":"extraction.d.ts","sourceRoot":"","sources":["../src/extraction.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,+CAA+C;IAC/C,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;IAC3C,2DAA2D;IAC3D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,kDAAkD;IAClD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,mDAAmD;IACnD,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,iCAAiC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { type
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
1
|
+
export { type AuthConnector, type AuthCredentials, type AuthError, } from './connectors/connector.js';
|
|
2
|
+
export { createJwtConnector, type JwtConnectorOptions, } from './connectors/jwt.js';
|
|
3
|
+
export { authGate } from './auth-gate.js';
|
|
4
|
+
export { authProvision } from './auth-provision.js';
|
|
5
5
|
export { authVerify } from './trails/auth-verify.js';
|
|
6
6
|
export { PermitError } from './errors.js';
|
|
7
7
|
export { type PermitExtractionInput } from './extraction.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,SAAS,GACf,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,kBAAkB,EAClB,KAAK,mBAAmB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,KAAK,MAAM,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export {} from './
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
1
|
+
export {} from './connectors/connector.js';
|
|
2
|
+
export { createJwtConnector, } from './connectors/jwt.js';
|
|
3
|
+
export { authGate } from './auth-gate.js';
|
|
4
|
+
export { authProvision } from './auth-provision.js';
|
|
5
5
|
export { authVerify } from './trails/auth-verify.js';
|
|
6
6
|
export { PermitError } from './errors.js';
|
|
7
7
|
export {} from './extraction.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,kBAAkB,GAEnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAA8B,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAe,SAAS,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,eAAe,EAAyB,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/permit.d.ts
CHANGED
|
@@ -9,8 +9,8 @@ export interface Permit extends BasePermit {
|
|
|
9
9
|
* Type-safe accessor for `ctx.permit` with a downcast to `Permit`.
|
|
10
10
|
*
|
|
11
11
|
* `TrailContext.permit` is typed as `BasePermit` (id + scopes). This accessor
|
|
12
|
-
* returns the full `Permit` when the auth
|
|
13
|
-
* the auth
|
|
12
|
+
* returns the full `Permit` when the auth gate has set one. Safe because
|
|
13
|
+
* the auth gate is the only writer and always sets a full `Permit`.
|
|
14
14
|
*
|
|
15
15
|
* @example
|
|
16
16
|
* ```typescript
|
package/dist/permit.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Type-safe accessor for `ctx.permit` with a downcast to `Permit`.
|
|
3
3
|
*
|
|
4
4
|
* `TrailContext.permit` is typed as `BasePermit` (id + scopes). This accessor
|
|
5
|
-
* returns the full `Permit` when the auth
|
|
6
|
-
* the auth
|
|
5
|
+
* returns the full `Permit` when the auth gate has set one. Safe because
|
|
6
|
+
* the auth gate is the only writer and always sets a full `Permit`.
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
9
|
* ```typescript
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Infrastructure trail that verifies a bearer token and returns the resolved permit.
|
|
3
3
|
*
|
|
4
|
-
* Reads the auth
|
|
5
|
-
* bootstrap (e.g. JWT with HMAC secret). The mock
|
|
6
|
-
* a null permit, so `testAll(app)` works without configuration.
|
|
4
|
+
* Reads the auth connector from `authProvision` — the connector is configured
|
|
5
|
+
* at bootstrap (e.g. JWT with HMAC secret). The mock connector always
|
|
6
|
+
* succeeds with a null permit, so `testAll(app)` works without configuration.
|
|
7
7
|
*/
|
|
8
8
|
export declare const authVerify: import("@ontrails/core").Trail<{
|
|
9
9
|
token: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-verify.d.ts","sourceRoot":"","sources":["../../src/trails/auth-verify.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"auth-verify.d.ts","sourceRoot":"","sources":["../../src/trails/auth-verify.ts"],"names":[],"mappings":"AA4CA;;;;;;GAMG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;EAiDrB,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Result,
|
|
1
|
+
import { Result, TRAILHEAD_KEY, trail } from '@ontrails/core';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import {
|
|
3
|
+
import { authProvision } from '../auth-provision.js';
|
|
4
4
|
const permitSchema = z.object({
|
|
5
5
|
id: z.string(),
|
|
6
6
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
@@ -23,42 +23,25 @@ const toOutputPermit = (permit) => ({
|
|
|
23
23
|
id: permit.id,
|
|
24
24
|
scopes: [...permit.scopes],
|
|
25
25
|
});
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
return
|
|
26
|
+
const isTrailhead = (value) => value === 'http' || value === 'mcp' || value === 'cli';
|
|
27
|
+
const getTrailhead = (ctx) => {
|
|
28
|
+
const trailhead = ctx.extensions?.[TRAILHEAD_KEY];
|
|
29
|
+
return isTrailhead(trailhead) ? trailhead : 'http';
|
|
30
30
|
};
|
|
31
31
|
/**
|
|
32
32
|
* Infrastructure trail that verifies a bearer token and returns the resolved permit.
|
|
33
33
|
*
|
|
34
|
-
* Reads the auth
|
|
35
|
-
* bootstrap (e.g. JWT with HMAC secret). The mock
|
|
36
|
-
* a null permit, so `testAll(app)` works without configuration.
|
|
34
|
+
* Reads the auth connector from `authProvision` — the connector is configured
|
|
35
|
+
* at bootstrap (e.g. JWT with HMAC secret). The mock connector always
|
|
36
|
+
* succeeds with a null permit, so `testAll(app)` works without configuration.
|
|
37
37
|
*/
|
|
38
38
|
export const authVerify = trail('auth.verify', {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
name: 'Verify a token',
|
|
43
|
-
},
|
|
44
|
-
],
|
|
45
|
-
input: z.object({
|
|
46
|
-
token: z.string().min(1).describe('Bearer token to verify'),
|
|
47
|
-
}),
|
|
48
|
-
intent: 'read',
|
|
49
|
-
metadata: { category: 'infrastructure' },
|
|
50
|
-
output: z.object({
|
|
51
|
-
error: z.string().optional(),
|
|
52
|
-
errorCode: authErrorCodeSchema.optional(),
|
|
53
|
-
permit: permitSchema.optional(),
|
|
54
|
-
valid: z.boolean(),
|
|
55
|
-
}),
|
|
56
|
-
run: async (input, ctx) => {
|
|
57
|
-
const adapter = authService.from(ctx);
|
|
58
|
-
const result = await adapter.authenticate({
|
|
39
|
+
blaze: async (input, ctx) => {
|
|
40
|
+
const connector = authProvision.from(ctx);
|
|
41
|
+
const result = await connector.authenticate({
|
|
59
42
|
bearerToken: input.token,
|
|
60
43
|
requestId: ctx.requestId,
|
|
61
|
-
|
|
44
|
+
trailhead: getTrailhead(ctx),
|
|
62
45
|
});
|
|
63
46
|
if (result.isErr()) {
|
|
64
47
|
return Result.ok({
|
|
@@ -80,6 +63,23 @@ export const authVerify = trail('auth.verify', {
|
|
|
80
63
|
valid: true,
|
|
81
64
|
});
|
|
82
65
|
},
|
|
83
|
-
|
|
66
|
+
examples: [
|
|
67
|
+
{
|
|
68
|
+
input: { token: 'test-token' },
|
|
69
|
+
name: 'Verify a token',
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
input: z.object({
|
|
73
|
+
token: z.string().min(1).describe('Bearer token to verify'),
|
|
74
|
+
}),
|
|
75
|
+
intent: 'read',
|
|
76
|
+
meta: { category: 'infrastructure' },
|
|
77
|
+
output: z.object({
|
|
78
|
+
error: z.string().optional(),
|
|
79
|
+
errorCode: authErrorCodeSchema.optional(),
|
|
80
|
+
permit: permitSchema.optional(),
|
|
81
|
+
valid: z.boolean(),
|
|
82
|
+
}),
|
|
83
|
+
provisions: [authProvision],
|
|
84
84
|
});
|
|
85
85
|
//# sourceMappingURL=auth-verify.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-verify.js","sourceRoot":"","sources":["../../src/trails/auth-verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"auth-verify.js","sourceRoot":"","sources":["../../src/trails/auth-verify.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ontrails/permits",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.14",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./src/index.ts",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"clean": "rm -rf dist *.tsbuildinfo"
|
|
16
16
|
},
|
|
17
17
|
"peerDependencies": {
|
|
18
|
-
"@ontrails/core": "^1.0.0-beta.
|
|
18
|
+
"@ontrails/core": "^1.0.0-beta.13",
|
|
19
19
|
"zod": "^4.3.5"
|
|
20
20
|
}
|
|
21
21
|
}
|
package/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["./src/
|
|
1
|
+
{"root":["./src/auth-gate.ts","./src/auth-provision.ts","./src/errors.ts","./src/extraction.ts","./src/index.ts","./src/permit.ts","./src/rules.ts","./src/testing.ts","./src/connectors/connector.ts","./src/connectors/jwt.ts","./src/trails/auth-verify.ts"],"version":"5.9.3"}
|