@fabrika/jwks 0.2.0 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fabrika/jwks",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,7 +26,8 @@
26
26
  "test": "bun test"
27
27
  },
28
28
  "dependencies": {
29
- "@fabrika/auth-core": "^0.2.0",
29
+ "zod": "^3.25.76",
30
+ "@fabrika/auth-core": "^0.3.1",
30
31
  "jose": "^5.9.0"
31
32
  }
32
33
  }
package/src/index.ts CHANGED
@@ -6,5 +6,6 @@
6
6
  // the code because it is deliberately dependency-free (no `jose`) for its browser-side consumers.
7
7
  // So the implementation lives here and both wrap it with their own construction shape.
8
8
 
9
+ export { parseJwks } from './parse'
9
10
  export { createJwksCache, JWKS_REFETCH_COOLDOWN_SECONDS, JWKS_TTL_SECONDS, TokenVerifier } from './verifier'
10
11
  export type { JwksCache, TokenVerifierOptions, VerifyResult } from './verifier'
package/src/parse.ts ADDED
@@ -0,0 +1,36 @@
1
+ import type { Jwks } from '@fabrika/auth-core'
2
+ import { z } from 'zod'
3
+
4
+ const publicJwkSchema = z.preprocess(
5
+ (raw) => {
6
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) return raw
7
+ // Binding responses can carry prototypes; inherited fields are not part of a public key.
8
+ const fields = Object.fromEntries(
9
+ ['kty', 'crv', 'x', 'y', 'kid', 'alg', 'use']
10
+ .filter(field => Object.hasOwn(raw, field))
11
+ .map(field => [field, Reflect.get(raw, field)]),
12
+ )
13
+ Object.setPrototypeOf(fields, null)
14
+ return fields
15
+ },
16
+ z.object({
17
+ kty: z.literal('EC'),
18
+ crv: z.string().optional(),
19
+ x: z.string().optional(),
20
+ y: z.string().optional(),
21
+ kid: z.string().optional(),
22
+ alg: z.string().optional(),
23
+ use: z.string().optional(),
24
+ }).refine(key => Object.values(key).every(value => value !== undefined)),
25
+ )
26
+
27
+ const jwksSchema = z.preprocess((body) => {
28
+ if (typeof body !== 'object' || body === null || Array.isArray(body)) return body
29
+ return { keys: Object.hasOwn(body, 'keys') ? Reflect.get(body, 'keys') : undefined }
30
+ }, z.object({ keys: z.array(publicJwkSchema) }))
31
+
32
+ /** Reject the whole set when a member cannot be represented; dropping one would misreport an outage as an invalid token. */
33
+ export function parseJwks(body: unknown): Jwks | null {
34
+ const result = jwksSchema.safeParse(body)
35
+ return result.success ? result.data : null
36
+ }