@t4h.framework/jwks 0.6.0 → 0.7.1
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/.ai/skills/framework-jwks/SKILL.md +1 -1
- package/CHANGELOG.md +33 -0
- package/README.md +1 -1
- package/dist/jwks-callback.d.ts +2 -2
- package/dist/jwks-callback.d.ts.map +1 -1
- package/dist/jwks-callback.js +57 -2
- package/dist/jwks-callback.js.map +1 -1
- package/package.json +3 -3
|
@@ -27,7 +27,7 @@ Package path: `framework/packages/jwks`. See [README.md](../../../README.md) for
|
|
|
27
27
|
|-------|---------|
|
|
28
28
|
| `@t4h.framework/jwks` | `JWKSAuthorization`, `JWKSAuthorizationContext`, `JWKSAuthorizationManifest`, `JWKSAlgorithm`, re-exports authorize module |
|
|
29
29
|
| `@t4h.framework/jwks/authorize` | Default async handler: `(context) => Promise<boolean>` |
|
|
30
|
-
| `@t4h.framework/jwks/callback` | Default export `jwksCallback`: `(auth,
|
|
30
|
+
| `@t4h.framework/jwks/callback` | Default export `jwksCallback`: `(auth, delivery) => Promise<boolean>`, the authorizer hosts pass to the core `AsyncActivityCallback.authorize` for `jwt` (bearer JWT) and `jwks` (detached signature over the body, key resolved by `kid` from a JWKS URL) |
|
|
31
31
|
|
|
32
32
|
```typescript
|
|
33
33
|
import {
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# @t4h.framework/jwks
|
|
2
2
|
|
|
3
|
+
## 0.7.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`9449e4e`](https://github.com/tech4humans-brasil/framework/commit/9449e4e9889f42dea1d52418140f47d25dff0535), [`9449e4e`](https://github.com/tech4humans-brasil/framework/commit/9449e4e9889f42dea1d52418140f47d25dff0535)]:
|
|
8
|
+
- @t4h.framework/core@0.15.0
|
|
9
|
+
|
|
10
|
+
## 0.7.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- [#170](https://github.com/tech4humans-brasil/framework/pull/170) [`aa72268`](https://github.com/tech4humans-brasil/framework/commit/aa72268d040a743743cac31cc14e26b8620b0e3f) Thanks [@gusteycamargo](https://github.com/gusteycamargo)! - Adds the `jwks` callback auth: a detached signature over the callback body,
|
|
15
|
+
verified with the public key the `kid` resolves to at a JWKS URL — the way Amber
|
|
16
|
+
signs its webhooks.
|
|
17
|
+
|
|
18
|
+
**core**: `AsyncActivityCallbackAuthJwks` joins `AsyncActivityCallbackAuth`
|
|
19
|
+
(`jwksUri`, `header`, `kid`/`kidHeader`, `algorithm`/`algorithmHeader`,
|
|
20
|
+
`signatureFormat`/`signatureFormatHeader`, `timestampHeader`,
|
|
21
|
+
`toleranceInSeconds`, `signedPayload` as a template over `{timestamp}` and
|
|
22
|
+
`{body}`).
|
|
23
|
+
|
|
24
|
+
**jwks**: `jwksCallback` (default of `@t4h.framework/jwks/callback`) now serves
|
|
25
|
+
both `jwt` and `jwks`. Hosts pass it as `{ jwt: jwksCallback, jwks: jwksCallback }`.
|
|
26
|
+
|
|
27
|
+
**dev**: loads `@t4h.framework/jwks` for the `jwks` type as well.
|
|
28
|
+
|
|
29
|
+
**webhook**: documents the new type.
|
|
30
|
+
|
|
31
|
+
### Patch Changes
|
|
32
|
+
|
|
33
|
+
- Updated dependencies [[`aa72268`](https://github.com/tech4humans-brasil/framework/commit/aa72268d040a743743cac31cc14e26b8620b0e3f)]:
|
|
34
|
+
- @t4h.framework/core@0.14.0
|
|
35
|
+
|
|
3
36
|
## 0.6.0
|
|
4
37
|
|
|
5
38
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Requires `@t4h.framework/core` (same major line as this package).
|
|
|
12
12
|
|------------------|---------|
|
|
13
13
|
| `@t4h.framework/jwks` | `JWKSAuthorization`, `JWKSAuthorizationContext`, and related types |
|
|
14
14
|
| `@t4h.framework/jwks/authorize` | Default async handler invoked by the runtime with the manifest context |
|
|
15
|
-
| `@t4h.framework/jwks/callback` | Default export `jwksCallback`: `jwt` callback authorizer for the core `AsyncActivityCallback.authorize`
|
|
15
|
+
| `@t4h.framework/jwks/callback` | Default export `jwksCallback`: the `jwt` (bearer JWT) and `jwks` (detached signature verified with a JWKS key) callback authorizer for the core `AsyncActivityCallback.authorize` |
|
|
16
16
|
|
|
17
17
|
## `JWKSAuthorization`
|
|
18
18
|
|
package/dist/jwks-callback.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { AsyncActivityCallback, type AsyncActivityCallbackAuthJwt } from '@t4h.framework/core';
|
|
2
|
-
export default function jwksCallback(auth: AsyncActivityCallbackAuthJwt,
|
|
1
|
+
import { AsyncActivityCallback, type AsyncActivityCallbackAuthJwks, type AsyncActivityCallbackAuthJwt } from '@t4h.framework/core';
|
|
2
|
+
export default function jwksCallback(auth: AsyncActivityCallbackAuthJwt | AsyncActivityCallbackAuthJwks, delivery: AsyncActivityCallback.Delivery): Promise<boolean>;
|
|
3
3
|
//# sourceMappingURL=jwks-callback.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwks-callback.d.ts","sourceRoot":"","sources":["../src/jwks-callback.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,KAAK,4BAA4B,EAClC,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"jwks-callback.d.ts","sourceRoot":"","sources":["../src/jwks-callback.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,KAAK,6BAA6B,EAClC,KAAK,4BAA4B,EAClC,MAAM,qBAAqB,CAAA;AAyG5B,wBAA8B,YAAY,CACxC,IAAI,EAAE,4BAA4B,GAAG,6BAA6B,EAClE,QAAQ,EAAE,qBAAqB,CAAC,QAAQ,GACvC,OAAO,CAAC,OAAO,CAAC,CAIlB"}
|
package/dist/jwks-callback.js
CHANGED
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
import { AsyncActivityCallback, } from '@t4h.framework/core';
|
|
2
2
|
import jwks from './jwks-authorize.js';
|
|
3
|
-
|
|
4
|
-
const
|
|
3
|
+
function isWithinTolerance(timestamp, toleranceInSeconds) {
|
|
4
|
+
const value = timestamp.trim();
|
|
5
|
+
if (!value)
|
|
6
|
+
return false;
|
|
7
|
+
const signedAt = /^\d+$/.test(value)
|
|
8
|
+
? value.length >= 13
|
|
9
|
+
? Number(value)
|
|
10
|
+
: Number(value) * 1000
|
|
11
|
+
: Date.parse(value);
|
|
12
|
+
if (Number.isNaN(signedAt))
|
|
13
|
+
return false;
|
|
14
|
+
return Math.abs(Date.now() - signedAt) / 1000 <= toleranceInSeconds;
|
|
15
|
+
}
|
|
16
|
+
function fromHeaderOrValue(headers, value, header) {
|
|
17
|
+
if (value !== undefined)
|
|
18
|
+
return value;
|
|
19
|
+
if (!header)
|
|
20
|
+
return undefined;
|
|
21
|
+
return AsyncActivityCallback.getHeader(headers, header);
|
|
22
|
+
}
|
|
23
|
+
async function verifyJwt(auth, delivery) {
|
|
24
|
+
const token = AsyncActivityCallback.getBearerToken(delivery.headers, auth.header);
|
|
5
25
|
if (!token)
|
|
6
26
|
return false;
|
|
7
27
|
try {
|
|
@@ -17,4 +37,39 @@ export default async function jwksCallback(auth, request) {
|
|
|
17
37
|
return false;
|
|
18
38
|
}
|
|
19
39
|
}
|
|
40
|
+
async function verifyDetachedSignature(auth, delivery) {
|
|
41
|
+
const { headers } = delivery;
|
|
42
|
+
const signature = AsyncActivityCallback.getHeader(headers, auth.header);
|
|
43
|
+
if (!signature)
|
|
44
|
+
return false;
|
|
45
|
+
const timestamp = auth.timestampHeader
|
|
46
|
+
? AsyncActivityCallback.getHeader(headers, auth.timestampHeader)
|
|
47
|
+
: undefined;
|
|
48
|
+
if (auth.timestampHeader && !timestamp)
|
|
49
|
+
return false;
|
|
50
|
+
if (auth.toleranceInSeconds !== undefined &&
|
|
51
|
+
!isWithinTolerance(timestamp ?? '', auth.toleranceInSeconds))
|
|
52
|
+
return false;
|
|
53
|
+
const rawPayload = (auth.signedPayload ?? '{body}')
|
|
54
|
+
.replaceAll('{timestamp}', timestamp ?? '')
|
|
55
|
+
.replaceAll('{body}', delivery.rawBody);
|
|
56
|
+
try {
|
|
57
|
+
return await jwks({
|
|
58
|
+
url: auth.jwksUri,
|
|
59
|
+
signature,
|
|
60
|
+
rawPayload,
|
|
61
|
+
kid: fromHeaderOrValue(headers, auth.kid, auth.kidHeader),
|
|
62
|
+
algorithm: fromHeaderOrValue(headers, auth.algorithm, auth.algorithmHeader),
|
|
63
|
+
signatureFormat: fromHeaderOrValue(headers, auth.signatureFormat, auth.signatureFormatHeader) ?? 'hex',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export default async function jwksCallback(auth, delivery) {
|
|
71
|
+
if (auth.type === 'jwks')
|
|
72
|
+
return verifyDetachedSignature(auth, delivery);
|
|
73
|
+
return verifyJwt(auth, delivery);
|
|
74
|
+
}
|
|
20
75
|
//# sourceMappingURL=jwks-callback.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwks-callback.js","sourceRoot":"","sources":["../src/jwks-callback.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,
|
|
1
|
+
{"version":3,"file":"jwks-callback.js","sourceRoot":"","sources":["../src/jwks-callback.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@t4h.framework/jwks",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "JWKS module for the T4H Framework authorization",
|
|
5
5
|
"homepage": "https://github.com/tech4humans-brasil/framework/tree/main/packages/jwks",
|
|
6
6
|
"bugs": "https://github.com/tech4humans-brasil/framework/issues",
|
|
@@ -41,13 +41,13 @@
|
|
|
41
41
|
"test:watch": "vitest"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@t4h.framework/core": "^0.
|
|
44
|
+
"@t4h.framework/core": "^0.15.0",
|
|
45
45
|
"@types/jsonwebtoken": "^9",
|
|
46
46
|
"typescript": "^5.9.3",
|
|
47
47
|
"vitest": "^4.0.18"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@t4h.framework/core": "^0.
|
|
50
|
+
"@t4h.framework/core": "^0.15.0"
|
|
51
51
|
},
|
|
52
52
|
"packageManager": "yarn@4.12.0",
|
|
53
53
|
"engines": {
|