@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.
@@ -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, request) => Promise<boolean>`, the `jwt` authorizer hosts pass to the core `AsyncActivityCallback.authorize` |
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` (`pending({ auth: { type: 'jwt' } })`) |
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
 
@@ -1,3 +1,3 @@
1
- import { AsyncActivityCallback, type AsyncActivityCallbackAuthJwt } from '@t4h.framework/core';
2
- export default function jwksCallback(auth: AsyncActivityCallbackAuthJwt, request: AsyncActivityCallback.Delivery): Promise<boolean>;
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;AAI5B,wBAA8B,YAAY,CACxC,IAAI,EAAE,4BAA4B,EAClC,OAAO,EAAE,qBAAqB,CAAC,QAAQ,GACtC,OAAO,CAAC,OAAO,CAAC,CAmBlB"}
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"}
@@ -1,7 +1,27 @@
1
1
  import { AsyncActivityCallback, } from '@t4h.framework/core';
2
2
  import jwks from './jwks-authorize.js';
3
- export default async function jwksCallback(auth, request) {
4
- const token = AsyncActivityCallback.getBearerToken(request.headers, auth.header);
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,GAEtB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,IAAI,MAAM,qBAAqB,CAAA;AAEtC,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,YAAY,CACxC,IAAkC,EAClC,OAAuC;IAEvC,MAAM,KAAK,GAAG,qBAAqB,CAAC,cAAc,CAChD,OAAO,CAAC,OAAO,EACf,IAAI,CAAC,MAAM,CACZ,CAAA;IAED,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAA;IAExB,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,CAAC;YAChB,GAAG,EAAE,IAAI,CAAC,OAAO;YACjB,SAAS,EAAE,KAAK;YAChB,UAAU,EAAE,EAAE;YACd,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC,CAAA;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC"}
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.6.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.13.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.13.0"
50
+ "@t4h.framework/core": "^0.15.0"
51
51
  },
52
52
  "packageManager": "yarn@4.12.0",
53
53
  "engines": {