@keycardai/oauth 0.2.0 → 0.4.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.
Files changed (98) hide show
  1. package/README.md +91 -4
  2. package/dist/cjs/credentials.d.ts +22 -0
  3. package/dist/cjs/credentials.d.ts.map +1 -0
  4. package/dist/cjs/credentials.js +3 -0
  5. package/dist/cjs/credentials.js.map +1 -0
  6. package/dist/cjs/errors.d.ts +23 -0
  7. package/dist/cjs/errors.d.ts.map +1 -1
  8. package/dist/cjs/errors.js +42 -1
  9. package/dist/cjs/errors.js.map +1 -1
  10. package/dist/cjs/index.d.ts +7 -3
  11. package/dist/cjs/index.d.ts.map +1 -1
  12. package/dist/cjs/index.js +10 -1
  13. package/dist/cjs/index.js.map +1 -1
  14. package/dist/cjs/jwt/substituteUser.d.ts +15 -0
  15. package/dist/cjs/jwt/substituteUser.d.ts.map +1 -0
  16. package/dist/cjs/jwt/substituteUser.js +29 -0
  17. package/dist/cjs/jwt/substituteUser.js.map +1 -0
  18. package/dist/cjs/jwt/verifier.d.ts +22 -1
  19. package/dist/cjs/jwt/verifier.d.ts.map +1 -1
  20. package/dist/cjs/jwt/verifier.js +101 -9
  21. package/dist/cjs/jwt/verifier.js.map +1 -1
  22. package/dist/cjs/keyring.d.ts +6 -0
  23. package/dist/cjs/keyring.d.ts.map +1 -1
  24. package/dist/cjs/keyring.js +11 -0
  25. package/dist/cjs/keyring.js.map +1 -1
  26. package/dist/cjs/server/accessContext.d.ts +26 -0
  27. package/dist/cjs/server/accessContext.d.ts.map +1 -0
  28. package/dist/cjs/server/accessContext.js +105 -0
  29. package/dist/cjs/server/accessContext.js.map +1 -0
  30. package/dist/cjs/server/accessToken.d.ts +8 -0
  31. package/dist/cjs/server/accessToken.d.ts.map +1 -0
  32. package/dist/cjs/server/accessToken.js +3 -0
  33. package/dist/cjs/server/accessToken.js.map +1 -0
  34. package/dist/cjs/server/clientSecret.d.ts +14 -0
  35. package/dist/cjs/server/clientSecret.d.ts.map +1 -0
  36. package/dist/cjs/server/clientSecret.js +76 -0
  37. package/dist/cjs/server/clientSecret.js.map +1 -0
  38. package/dist/cjs/server/index.d.ts +8 -0
  39. package/dist/cjs/server/index.d.ts.map +1 -0
  40. package/dist/cjs/server/index.js +10 -0
  41. package/dist/cjs/server/index.js.map +1 -0
  42. package/dist/cjs/server/tokenVerifier.d.ts +49 -0
  43. package/dist/cjs/server/tokenVerifier.d.ts.map +1 -0
  44. package/dist/cjs/server/tokenVerifier.js +118 -0
  45. package/dist/cjs/server/tokenVerifier.js.map +1 -0
  46. package/dist/cjs/tokenExchange.d.ts +27 -1
  47. package/dist/cjs/tokenExchange.d.ts.map +1 -1
  48. package/dist/cjs/tokenExchange.js +44 -6
  49. package/dist/cjs/tokenExchange.js.map +1 -1
  50. package/dist/esm/credentials.d.ts +22 -0
  51. package/dist/esm/credentials.d.ts.map +1 -0
  52. package/dist/esm/credentials.js +2 -0
  53. package/dist/esm/credentials.js.map +1 -0
  54. package/dist/esm/errors.d.ts +23 -0
  55. package/dist/esm/errors.d.ts.map +1 -1
  56. package/dist/esm/errors.js +39 -0
  57. package/dist/esm/errors.js.map +1 -1
  58. package/dist/esm/index.d.ts +7 -3
  59. package/dist/esm/index.d.ts.map +1 -1
  60. package/dist/esm/index.js +4 -2
  61. package/dist/esm/index.js.map +1 -1
  62. package/dist/esm/jwt/substituteUser.d.ts +15 -0
  63. package/dist/esm/jwt/substituteUser.d.ts.map +1 -0
  64. package/dist/esm/jwt/substituteUser.js +26 -0
  65. package/dist/esm/jwt/substituteUser.js.map +1 -0
  66. package/dist/esm/jwt/verifier.d.ts +22 -1
  67. package/dist/esm/jwt/verifier.d.ts.map +1 -1
  68. package/dist/esm/jwt/verifier.js +101 -9
  69. package/dist/esm/jwt/verifier.js.map +1 -1
  70. package/dist/esm/keyring.d.ts +6 -0
  71. package/dist/esm/keyring.d.ts.map +1 -1
  72. package/dist/esm/keyring.js +11 -0
  73. package/dist/esm/keyring.js.map +1 -1
  74. package/dist/esm/server/accessContext.d.ts +26 -0
  75. package/dist/esm/server/accessContext.d.ts.map +1 -0
  76. package/dist/esm/server/accessContext.js +101 -0
  77. package/dist/esm/server/accessContext.js.map +1 -0
  78. package/dist/esm/server/accessToken.d.ts +8 -0
  79. package/dist/esm/server/accessToken.d.ts.map +1 -0
  80. package/dist/esm/server/accessToken.js +2 -0
  81. package/dist/esm/server/accessToken.js.map +1 -0
  82. package/dist/esm/server/clientSecret.d.ts +14 -0
  83. package/dist/esm/server/clientSecret.d.ts.map +1 -0
  84. package/dist/esm/server/clientSecret.js +72 -0
  85. package/dist/esm/server/clientSecret.js.map +1 -0
  86. package/dist/esm/server/index.d.ts +8 -0
  87. package/dist/esm/server/index.d.ts.map +1 -0
  88. package/dist/esm/server/index.js +4 -0
  89. package/dist/esm/server/index.js.map +1 -0
  90. package/dist/esm/server/tokenVerifier.d.ts +49 -0
  91. package/dist/esm/server/tokenVerifier.d.ts.map +1 -0
  92. package/dist/esm/server/tokenVerifier.js +114 -0
  93. package/dist/esm/server/tokenVerifier.js.map +1 -0
  94. package/dist/esm/tokenExchange.d.ts +27 -1
  95. package/dist/esm/tokenExchange.d.ts.map +1 -1
  96. package/dist/esm/tokenExchange.js +43 -5
  97. package/dist/esm/tokenExchange.js.map +1 -1
  98. package/package.json +37 -2
package/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # @keycardai/oauth
2
2
 
3
- Pure OAuth 2.0 primitives for Keycard JWKS key management, JWT signing/verification, authorization server discovery, and token exchange. **Zero MCP dependencies.**
3
+ > **Preview.** This SDK has not reached parity with the Keycard Python
4
+ > SDK. APIs may change between minor versions. The preview label will
5
+ > be removed once feature parity is reached.
6
+
7
+ OAuth 2.0 primitives for Keycard: JWKS key management, JWT signing and verification, authorization server discovery, RFC 8693 token exchange (including impersonation), and server-tier primitives (`AccessContext`, `TokenVerifier`, `ClientSecret`) with multi-zone support. **Zero MCP dependencies.**
4
8
 
5
9
  This is the foundational layer of the [Keycard TypeScript SDK](../../README.md). If you're building an MCP server, you probably want [`@keycardai/mcp`](../mcp/) instead, which includes this package as a dependency.
6
10
 
@@ -28,8 +32,13 @@ const token = await signer.sign({
28
32
  scope: "read write",
29
33
  });
30
34
 
31
- // Verify a JWT
32
- const verifier = new JWTVerifier(keyring);
35
+ // Verify a JWT. `issuers` is required — it binds the verifier to the
36
+ // authorization server(s) you trust. Tokens with any other `iss` are
37
+ // rejected before the keyring is consulted.
38
+ const verifier = new JWTVerifier(keyring, {
39
+ issuers: "https://your-zone.keycard.cloud",
40
+ // audiences: "https://api.example.com", // optional
41
+ });
33
42
  const claims = await verifier.verify(token);
34
43
  ```
35
44
 
@@ -63,6 +72,70 @@ const response = await client.exchangeToken({
63
72
  console.log(response.accessToken);
64
73
  ```
65
74
 
75
+ ### Impersonation (substitute-user token exchange)
76
+
77
+ ```typescript
78
+ import { TokenExchangeClient } from "@keycardai/oauth/tokenExchange";
79
+
80
+ const client = new TokenExchangeClient("https://your-zone.keycard.cloud", {
81
+ clientId: "your-client-id",
82
+ clientSecret: "your-client-secret",
83
+ });
84
+
85
+ const response = await client.impersonate({
86
+ userIdentifier: "user@example.com",
87
+ resource: "https://graph.microsoft.com",
88
+ });
89
+
90
+ console.log(response.accessToken);
91
+ ```
92
+
93
+ Impersonation is a privileged operation gated by Keycard policy. The calling
94
+ application authenticates via client credentials, and the impersonated user
95
+ must have a delegated grant for the target resource.
96
+
97
+ ### Multi-Zone Credentials
98
+
99
+ ```typescript
100
+ import { TokenExchangeClient } from "@keycardai/oauth/tokenExchange";
101
+ import { ClientSecret } from "@keycardai/oauth/server";
102
+
103
+ const credential = new ClientSecret({
104
+ "zone-a": ["client-id-a", "client-secret-a"],
105
+ "zone-b": ["client-id-b", "client-secret-b"],
106
+ });
107
+
108
+ const client = new TokenExchangeClient("https://keycard.cloud", { credential });
109
+
110
+ const response = await client.exchangeToken(
111
+ { subjectToken: userToken, resource: "https://api.example.com" },
112
+ { zoneId: "zone-a" },
113
+ );
114
+ ```
115
+
116
+ ### Server-tier Token Verification
117
+
118
+ ```typescript
119
+ import { TokenVerifier } from "@keycardai/oauth/server";
120
+
121
+ const verifier = new TokenVerifier({
122
+ issuer: "https://your-zone.keycard.cloud",
123
+ requiredScopes: ["read"],
124
+ audience: "https://api.example.com",
125
+ });
126
+
127
+ const accessToken = await verifier.verifyToken(bearerToken);
128
+ if (!accessToken) {
129
+ // 401 Unauthorized
130
+ }
131
+ console.log(accessToken.clientId, accessToken.scopes);
132
+ ```
133
+
134
+ `verifyToken` returns `AccessToken | null`. Verification failures (bad signature,
135
+ expired token, missing scope, audience mismatch) return `null`; callers map that
136
+ to an HTTP 401. `verifyTokenForZone(token, zoneId)` enables per-zone validation
137
+ when the verifier is constructed with `enableMultiZone: true`.
138
+
66
139
  ## API Overview
67
140
 
68
141
  ### JWKS Key Management
@@ -86,7 +159,19 @@ console.log(response.accessToken);
86
159
  | Export | Import Path | Description |
87
160
  |---|---|---|
88
161
  | `fetchAuthorizationServerMetadata` | `@keycardai/oauth/discovery` | Fetches `.well-known/oauth-authorization-server` metadata |
89
- | `TokenExchangeClient` | `@keycardai/oauth/tokenExchange` | RFC 8693 token exchange client with auto-discovery |
162
+ | `TokenExchangeClient` | `@keycardai/oauth/tokenExchange` | RFC 8693 token exchange client with auto-discovery, plus `impersonate()` for substitute-user exchange |
163
+ | `TokenType` | `@keycardai/oauth/tokenExchange` | URN constants: `ACCESS_TOKEN`, `SUBSTITUTE_USER` |
164
+ | `buildSubstituteUserToken` | `@keycardai/oauth/jwt/substituteUser` | Builds the unsigned subject JWT for impersonation calls |
165
+
166
+ ### Server-tier Primitives
167
+
168
+ | Export | Import Path | Description |
169
+ |---|---|---|
170
+ | `TokenVerifier` | `@keycardai/oauth/server` | High-level JWT verifier with JWKS discovery, multi-zone, audience and scope validation; returns `AccessToken \| null` |
171
+ | `AccessToken` (type) | `@keycardai/oauth/server` | Verified token shape (`token`, `clientId`, `scopes`, `expiresAt?`, `resource?`) |
172
+ | `AccessContext` | `@keycardai/oauth/server` | Non-throwing per-resource token container with partial-error tracking |
173
+ | `ClientSecret` | `@keycardai/oauth/server` | Application credential provider; supports `(clientId, clientSecret)`, tuple, or `Record<zoneId, [id, secret]>` |
174
+ | `ApplicationCredential` (type) | `@keycardai/oauth/credentials` | Interface for credential providers |
90
175
 
91
176
  ### Errors
92
177
 
@@ -98,6 +183,8 @@ console.log(response.accessToken);
98
183
  | `OAuthError` | `@keycardai/oauth/errors` | OAuth error with error code and URI |
99
184
  | `InvalidTokenError` | `@keycardai/oauth/errors` | Token validation failure |
100
185
  | `InsufficientScopeError` | `@keycardai/oauth/errors` | Missing required scopes |
186
+ | `ResourceAccessError` | `@keycardai/oauth/errors` | Thrown by `AccessContext.access()` on missing or failed resource |
187
+ | `AuthProviderConfigurationError` | `@keycardai/oauth/errors` | Configuration guard for auth providers |
101
188
 
102
189
  ### Utilities
103
190
 
@@ -0,0 +1,22 @@
1
+ import type { TokenExchangeRequest } from "./tokenExchange.js";
2
+ /**
3
+ * Common interface for application-level credentials used in token exchange.
4
+ *
5
+ * Implementations live in downstream packages (@keycardai/mcp, @keycardai/cloudflare)
6
+ * because they depend on platform-specific APIs (Node.js fs, Cloudflare Workers, etc.).
7
+ *
8
+ * The optional `zoneId` parameter routes per-zone credentials in multi-zone deployments.
9
+ * Implementations that ignore the zone (single-zone) are accepted by the interface.
10
+ */
11
+ export interface ApplicationCredential {
12
+ getAuth(zoneId?: string): {
13
+ clientId: string;
14
+ clientSecret: string;
15
+ } | null;
16
+ prepareTokenExchangeRequest(subjectToken: string, resource: string, options?: {
17
+ tokenEndpoint?: string;
18
+ authInfo?: Record<string, string>;
19
+ zoneId?: string;
20
+ }): Promise<TokenExchangeRequest>;
21
+ }
22
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE/D;;;;;;;;GAQG;AACH,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5E,2BAA2B,CACzB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GACvF,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAClC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/credentials.ts"],"names":[],"mappings":""}
@@ -16,4 +16,27 @@ export declare class InvalidTokenError extends OAuthError {
16
16
  export declare class InsufficientScopeError extends OAuthError {
17
17
  constructor(message: string, errorUri?: string);
18
18
  }
19
+ export type ErrorDetail = {
20
+ message: string;
21
+ code?: string;
22
+ description?: string;
23
+ rawError?: string;
24
+ };
25
+ export type ResourceAccessErrorType = "global_error" | "resource_error" | "missing_token";
26
+ export interface ResourceAccessErrorOptions {
27
+ resource?: string;
28
+ errorType?: ResourceAccessErrorType;
29
+ availableResources?: readonly string[];
30
+ errorDetails?: ErrorDetail | null;
31
+ }
32
+ export declare class ResourceAccessError extends Error {
33
+ readonly resource?: string;
34
+ readonly errorType?: ResourceAccessErrorType;
35
+ readonly availableResources?: readonly string[];
36
+ readonly errorDetails: ErrorDetail | null;
37
+ constructor(message?: string, options?: ResourceAccessErrorOptions);
38
+ }
39
+ export declare class AuthProviderConfigurationError extends Error {
40
+ constructor(message?: string);
41
+ }
19
42
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,SAAU,SAAQ,KAAK;gBAEhC,OAAO,EAAE,MAAM;CAIlB;AAED,qBAAa,eAAgB,SAAQ,SAAS;CAC7C;AAED,qBAAa,iBAAkB,SAAQ,SAAS;CAC/C;AAED,qBAAa,UAAW,SAAQ,KAAK;aAEjB,SAAS,EAAE,MAAM;aAEjB,QAAQ,CAAC,EAAE,MAAM;gBAFjB,SAAS,EAAE,MAAM,EACjC,OAAO,EAAE,MAAM,EACC,QAAQ,CAAC,EAAE,MAAM,YAAA;CAIpC;AAED,qBAAa,iBAAkB,SAAQ,UAAU;gBACnC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED,qBAAa,sBAAuB,SAAQ,UAAU;gBACxC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,SAAU,SAAQ,KAAK;gBAEhC,OAAO,EAAE,MAAM;CAIlB;AAED,qBAAa,eAAgB,SAAQ,SAAS;CAC7C;AAED,qBAAa,iBAAkB,SAAQ,SAAS;CAC/C;AAED,qBAAa,UAAW,SAAQ,KAAK;aAEjB,SAAS,EAAE,MAAM;aAEjB,QAAQ,CAAC,EAAE,MAAM;gBAFjB,SAAS,EAAE,MAAM,EACjC,OAAO,EAAE,MAAM,EACC,QAAQ,CAAC,EAAE,MAAM,YAAA;CAIpC;AAED,qBAAa,iBAAkB,SAAQ,UAAU;gBACnC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED,qBAAa,sBAAuB,SAAQ,UAAU;gBACxC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAC/B,cAAc,GACd,gBAAgB,GAChB,eAAe,CAAC;AAEpB,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,uBAAuB,CAAC;IACpC,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,YAAY,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CACnC;AAED,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,uBAAuB,CAAC;IAC7C,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChD,QAAQ,CAAC,YAAY,EAAE,WAAW,GAAG,IAAI,CAAC;gBAE9B,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,0BAA0B;CAQnE;AA4BD,qBAAa,8BAA+B,SAAQ,KAAK;gBAC3C,OAAO,CAAC,EAAE,MAAM;CAI7B"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.InsufficientScopeError = exports.InvalidTokenError = exports.OAuthError = exports.UnauthorizedError = exports.BadRequestError = exports.HTTPError = void 0;
3
+ exports.AuthProviderConfigurationError = exports.ResourceAccessError = exports.InsufficientScopeError = exports.InvalidTokenError = exports.OAuthError = exports.UnauthorizedError = exports.BadRequestError = exports.HTTPError = void 0;
4
4
  class HTTPError extends Error {
5
5
  constructor(message) {
6
6
  super(message);
@@ -33,4 +33,45 @@ class InsufficientScopeError extends OAuthError {
33
33
  }
34
34
  }
35
35
  exports.InsufficientScopeError = InsufficientScopeError;
36
+ class ResourceAccessError extends Error {
37
+ constructor(message, options) {
38
+ super(message ?? buildResourceAccessMessage(options));
39
+ this.name = "ResourceAccessError";
40
+ this.resource = options?.resource;
41
+ this.errorType = options?.errorType;
42
+ this.availableResources = options?.availableResources;
43
+ this.errorDetails = options?.errorDetails ?? null;
44
+ }
45
+ }
46
+ exports.ResourceAccessError = ResourceAccessError;
47
+ function buildResourceAccessMessage(options) {
48
+ if (!options?.errorType) {
49
+ return "Resource access denied or token not available";
50
+ }
51
+ const { resource, errorType, availableResources, errorDetails } = options;
52
+ const label = resource ? `'${resource}'` : "resource";
53
+ switch (errorType) {
54
+ case "global_error": {
55
+ const inner = errorDetails?.message ?? "Unknown global error";
56
+ return `Cannot access resource ${label}: global authentication error. ${inner}`;
57
+ }
58
+ case "resource_error": {
59
+ const inner = errorDetails?.message ?? "Unknown resource error";
60
+ return `Cannot access resource ${label}: ${inner}`;
61
+ }
62
+ case "missing_token": {
63
+ const list = availableResources && availableResources.length > 0
64
+ ? ` Available: ${availableResources.join(", ")}.`
65
+ : "";
66
+ return `No access token available for resource ${label}.${list}`;
67
+ }
68
+ }
69
+ }
70
+ class AuthProviderConfigurationError extends Error {
71
+ constructor(message) {
72
+ super(message ?? "AuthProvider configuration is invalid");
73
+ this.name = "AuthProviderConfigurationError";
74
+ }
75
+ }
76
+ exports.AuthProviderConfigurationError = AuthProviderConfigurationError;
36
77
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,SAAU,SAAQ,KAAK;IAClC,YACE,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;CACF;AAND,8BAMC;AAED,MAAa,eAAgB,SAAQ,SAAS;CAC7C;AADD,0CACC;AAED,MAAa,iBAAkB,SAAQ,SAAS;CAC/C;AADD,8CACC;AAED,MAAa,UAAW,SAAQ,KAAK;IACnC,YACkB,SAAiB,EACjC,OAAe,EACC,QAAiB;QAEjC,KAAK,CAAC,OAAO,CAAC,CAAC;QAJC,cAAS,GAAT,SAAS,CAAQ;QAEjB,aAAQ,GAAR,QAAQ,CAAS;IAGnC,CAAC;CACF;AARD,gCAQC;AAED,MAAa,iBAAkB,SAAQ,UAAU;IAC/C,YAAY,OAAe,EAAE,QAAiB;QAC5C,KAAK,CAAC,eAAe,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC5C,CAAC;CACF;AAJD,8CAIC;AAED,MAAa,sBAAuB,SAAQ,UAAU;IACpD,YAAY,OAAe,EAAE,QAAiB;QAC5C,KAAK,CAAC,oBAAoB,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACjD,CAAC;CACF;AAJD,wDAIC"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,SAAU,SAAQ,KAAK;IAClC,YACE,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;CACF;AAND,8BAMC;AAED,MAAa,eAAgB,SAAQ,SAAS;CAC7C;AADD,0CACC;AAED,MAAa,iBAAkB,SAAQ,SAAS;CAC/C;AADD,8CACC;AAED,MAAa,UAAW,SAAQ,KAAK;IACnC,YACkB,SAAiB,EACjC,OAAe,EACC,QAAiB;QAEjC,KAAK,CAAC,OAAO,CAAC,CAAC;QAJC,cAAS,GAAT,SAAS,CAAQ;QAEjB,aAAQ,GAAR,QAAQ,CAAS;IAGnC,CAAC;CACF;AARD,gCAQC;AAED,MAAa,iBAAkB,SAAQ,UAAU;IAC/C,YAAY,OAAe,EAAE,QAAiB;QAC5C,KAAK,CAAC,eAAe,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC5C,CAAC;CACF;AAJD,8CAIC;AAED,MAAa,sBAAuB,SAAQ,UAAU;IACpD,YAAY,OAAe,EAAE,QAAiB;QAC5C,KAAK,CAAC,oBAAoB,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACjD,CAAC;CACF;AAJD,wDAIC;AAqBD,MAAa,mBAAoB,SAAQ,KAAK;IAM5C,YAAY,OAAgB,EAAE,OAAoC;QAChE,KAAK,CAAC,OAAO,IAAI,0BAA0B,CAAC,OAAO,CAAC,CAAC,CAAC;QACtD,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,QAAQ,GAAG,OAAO,EAAE,QAAQ,CAAC;QAClC,IAAI,CAAC,SAAS,GAAG,OAAO,EAAE,SAAS,CAAC;QACpC,IAAI,CAAC,kBAAkB,GAAG,OAAO,EAAE,kBAAkB,CAAC;QACtD,IAAI,CAAC,YAAY,GAAG,OAAO,EAAE,YAAY,IAAI,IAAI,CAAC;IACpD,CAAC;CACF;AAdD,kDAcC;AAED,SAAS,0BAA0B,CAAC,OAAoC;IACtE,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC;QACxB,OAAO,+CAA+C,CAAC;IACzD,CAAC;IACD,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,kBAAkB,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;IAC1E,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC;IAEtD,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,cAAc,CAAC,CAAC,CAAC;YACpB,MAAM,KAAK,GAAG,YAAY,EAAE,OAAO,IAAI,sBAAsB,CAAC;YAC9D,OAAO,0BAA0B,KAAK,kCAAkC,KAAK,EAAE,CAAC;QAClF,CAAC;QACD,KAAK,gBAAgB,CAAC,CAAC,CAAC;YACtB,MAAM,KAAK,GAAG,YAAY,EAAE,OAAO,IAAI,wBAAwB,CAAC;YAChE,OAAO,0BAA0B,KAAK,KAAK,KAAK,EAAE,CAAC;QACrD,CAAC;QACD,KAAK,eAAe,CAAC,CAAC,CAAC;YACrB,MAAM,IAAI,GACR,kBAAkB,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC;gBACjD,CAAC,CAAC,eAAe,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;gBACjD,CAAC,CAAC,EAAE,CAAC;YACT,OAAO,0CAA0C,KAAK,IAAI,IAAI,EAAE,CAAC;QACnE,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAa,8BAA+B,SAAQ,KAAK;IACvD,YAAY,OAAgB;QAC1B,KAAK,CAAC,OAAO,IAAI,uCAAuC,CAAC,CAAC;QAC1D,IAAI,CAAC,IAAI,GAAG,gCAAgC,CAAC;IAC/C,CAAC;CACF;AALD,wEAKC"}
@@ -3,10 +3,14 @@ export { JWKSOAuthKeyring } from "./keyring.js";
3
3
  export { default as base64url } from "./base64url.js";
4
4
  export { fetchAuthorizationServerMetadata } from "./discovery.js";
5
5
  export type { OAuthAuthorizationServerMetadata } from "./discovery.js";
6
- export { HTTPError, BadRequestError, UnauthorizedError, OAuthError, InvalidTokenError, InsufficientScopeError } from "./errors.js";
6
+ export { HTTPError, BadRequestError, UnauthorizedError, OAuthError, InvalidTokenError, InsufficientScopeError, ResourceAccessError, AuthProviderConfigurationError, } from "./errors.js";
7
7
  export { JWTSigner } from "./jwt/signer.js";
8
8
  export type { JWTClaims } from "./jwt/signer.js";
9
9
  export { JWTVerifier } from "./jwt/verifier.js";
10
- export { TokenExchangeClient } from "./tokenExchange.js";
11
- export type { TokenExchangeRequest, TokenResponse, TokenExchangeClientOptions } from "./tokenExchange.js";
10
+ export { buildSubstituteUserToken } from "./jwt/substituteUser.js";
11
+ export { TokenExchangeClient, TokenType } from "./tokenExchange.js";
12
+ export type { TokenExchangeRequest, TokenResponse, TokenExchangeClientOptions, ExchangeOptions, ImpersonateRequest, } from "./tokenExchange.js";
13
+ export type { ApplicationCredential } from "./credentials.js";
14
+ export { AccessContext, TokenVerifier, ClientSecret } from "./server/index.js";
15
+ export type { ErrorDetail, AccessContextStatus, AccessToken, TokenVerifierOptions, ClientSecretCredentials, } from "./server/index.js";
12
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAC3G,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,gCAAgC,EAAE,MAAM,gBAAgB,CAAC;AAClE,YAAY,EAAE,gCAAgC,EAAE,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,iBAAiB,EAAE,UAAU,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACnI,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,YAAY,EAAE,oBAAoB,EAAE,aAAa,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAC3G,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,gCAAgC,EAAE,MAAM,gBAAgB,CAAC;AAClE,YAAY,EAAE,gCAAgC,EAAE,MAAM,gBAAgB,CAAC;AACvE,OAAO,EACL,SAAS,EACT,eAAe,EACf,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,mBAAmB,EACnB,8BAA8B,GAC/B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpE,YAAY,EACV,oBAAoB,EACpB,aAAa,EACb,0BAA0B,EAC1B,eAAe,EACf,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC/E,YAAY,EACV,WAAW,EACX,mBAAmB,EACnB,WAAW,EACX,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,mBAAmB,CAAC"}
package/dist/cjs/index.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.TokenExchangeClient = exports.JWTVerifier = exports.JWTSigner = exports.InsufficientScopeError = exports.InvalidTokenError = exports.OAuthError = exports.UnauthorizedError = exports.BadRequestError = exports.HTTPError = exports.fetchAuthorizationServerMetadata = exports.base64url = exports.JWKSOAuthKeyring = void 0;
6
+ exports.ClientSecret = exports.TokenVerifier = exports.AccessContext = exports.TokenType = exports.TokenExchangeClient = exports.buildSubstituteUserToken = exports.JWTVerifier = exports.JWTSigner = exports.AuthProviderConfigurationError = exports.ResourceAccessError = exports.InsufficientScopeError = exports.InvalidTokenError = exports.OAuthError = exports.UnauthorizedError = exports.BadRequestError = exports.HTTPError = exports.fetchAuthorizationServerMetadata = exports.base64url = exports.JWKSOAuthKeyring = void 0;
7
7
  var keyring_js_1 = require("./keyring.js");
8
8
  Object.defineProperty(exports, "JWKSOAuthKeyring", { enumerable: true, get: function () { return keyring_js_1.JWKSOAuthKeyring; } });
9
9
  var base64url_js_1 = require("./base64url.js");
@@ -17,10 +17,19 @@ Object.defineProperty(exports, "UnauthorizedError", { enumerable: true, get: fun
17
17
  Object.defineProperty(exports, "OAuthError", { enumerable: true, get: function () { return errors_js_1.OAuthError; } });
18
18
  Object.defineProperty(exports, "InvalidTokenError", { enumerable: true, get: function () { return errors_js_1.InvalidTokenError; } });
19
19
  Object.defineProperty(exports, "InsufficientScopeError", { enumerable: true, get: function () { return errors_js_1.InsufficientScopeError; } });
20
+ Object.defineProperty(exports, "ResourceAccessError", { enumerable: true, get: function () { return errors_js_1.ResourceAccessError; } });
21
+ Object.defineProperty(exports, "AuthProviderConfigurationError", { enumerable: true, get: function () { return errors_js_1.AuthProviderConfigurationError; } });
20
22
  var signer_js_1 = require("./jwt/signer.js");
21
23
  Object.defineProperty(exports, "JWTSigner", { enumerable: true, get: function () { return signer_js_1.JWTSigner; } });
22
24
  var verifier_js_1 = require("./jwt/verifier.js");
23
25
  Object.defineProperty(exports, "JWTVerifier", { enumerable: true, get: function () { return verifier_js_1.JWTVerifier; } });
26
+ var substituteUser_js_1 = require("./jwt/substituteUser.js");
27
+ Object.defineProperty(exports, "buildSubstituteUserToken", { enumerable: true, get: function () { return substituteUser_js_1.buildSubstituteUserToken; } });
24
28
  var tokenExchange_js_1 = require("./tokenExchange.js");
25
29
  Object.defineProperty(exports, "TokenExchangeClient", { enumerable: true, get: function () { return tokenExchange_js_1.TokenExchangeClient; } });
30
+ Object.defineProperty(exports, "TokenType", { enumerable: true, get: function () { return tokenExchange_js_1.TokenType; } });
31
+ var index_js_1 = require("./server/index.js");
32
+ Object.defineProperty(exports, "AccessContext", { enumerable: true, get: function () { return index_js_1.AccessContext; } });
33
+ Object.defineProperty(exports, "TokenVerifier", { enumerable: true, get: function () { return index_js_1.TokenVerifier; } });
34
+ Object.defineProperty(exports, "ClientSecret", { enumerable: true, get: function () { return index_js_1.ClientSecret; } });
26
35
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;AACA,2CAAgD;AAAvC,8GAAA,gBAAgB,OAAA;AACzB,+CAAsD;AAA7C,0HAAA,OAAO,OAAa;AAC7B,+CAAkE;AAAzD,gIAAA,gCAAgC,OAAA;AAEzC,yCAAmI;AAA1H,sGAAA,SAAS,OAAA;AAAE,4GAAA,eAAe,OAAA;AAAE,8GAAA,iBAAiB,OAAA;AAAE,uGAAA,UAAU,OAAA;AAAE,8GAAA,iBAAiB,OAAA;AAAE,mHAAA,sBAAsB,OAAA;AAC7G,6CAA4C;AAAnC,sGAAA,SAAS,OAAA;AAElB,iDAAgD;AAAvC,0GAAA,WAAW,OAAA;AACpB,uDAAyD;AAAhD,uHAAA,mBAAmB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;AACA,2CAAgD;AAAvC,8GAAA,gBAAgB,OAAA;AACzB,+CAAsD;AAA7C,0HAAA,OAAO,OAAa;AAC7B,+CAAkE;AAAzD,gIAAA,gCAAgC,OAAA;AAEzC,yCASqB;AARnB,sGAAA,SAAS,OAAA;AACT,4GAAA,eAAe,OAAA;AACf,8GAAA,iBAAiB,OAAA;AACjB,uGAAA,UAAU,OAAA;AACV,8GAAA,iBAAiB,OAAA;AACjB,mHAAA,sBAAsB,OAAA;AACtB,gHAAA,mBAAmB,OAAA;AACnB,2HAAA,8BAA8B,OAAA;AAEhC,6CAA4C;AAAnC,sGAAA,SAAS,OAAA;AAElB,iDAAgD;AAAvC,0GAAA,WAAW,OAAA;AACpB,6DAAmE;AAA1D,6HAAA,wBAAwB,OAAA;AACjC,uDAAoE;AAA3D,uHAAA,mBAAmB,OAAA;AAAE,6GAAA,SAAS,OAAA;AASvC,8CAA+E;AAAtE,yGAAA,aAAa,OAAA;AAAE,yGAAA,aAAa,OAAA;AAAE,wGAAA,YAAY,OAAA"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Build the substitute-user assertion sent as the `subject_token` of an
3
+ * impersonation token exchange (RFC 8693, Keycard vendor extension).
4
+ *
5
+ * This is NOT a signed JWT and is NOT a general-purpose JWT builder. The
6
+ * assertion's `alg: "none"` is intentional: the Keycard authorization server
7
+ * trusts the call by validating the requesting client's credentials and the
8
+ * vendor URN `urn:keycard:params:oauth:token-type:substitute-user`, not the
9
+ * subject token's signature. Authority comes from the calling application's
10
+ * client credentials plus the impersonation policy on the AS.
11
+ *
12
+ * For signing arbitrary JWTs, use `JWTSigner` from `@keycardai/oauth/jwt/signer`.
13
+ */
14
+ export declare function buildSubstituteUserToken(identifier: string): string;
15
+ //# sourceMappingURL=substituteUser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"substituteUser.d.ts","sourceRoot":"","sources":["../../../src/jwt/substituteUser.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAOnE"}
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildSubstituteUserToken = buildSubstituteUserToken;
4
+ const SUBSTITUTE_USER_HEADER = { typ: "vnd.kc.su+jwt", alg: "none" };
5
+ /**
6
+ * Build the substitute-user assertion sent as the `subject_token` of an
7
+ * impersonation token exchange (RFC 8693, Keycard vendor extension).
8
+ *
9
+ * This is NOT a signed JWT and is NOT a general-purpose JWT builder. The
10
+ * assertion's `alg: "none"` is intentional: the Keycard authorization server
11
+ * trusts the call by validating the requesting client's credentials and the
12
+ * vendor URN `urn:keycard:params:oauth:token-type:substitute-user`, not the
13
+ * subject token's signature. Authority comes from the calling application's
14
+ * client credentials plus the impersonation policy on the AS.
15
+ *
16
+ * For signing arbitrary JWTs, use `JWTSigner` from `@keycardai/oauth/jwt/signer`.
17
+ */
18
+ function buildSubstituteUserToken(identifier) {
19
+ if (!identifier) {
20
+ throw new Error("identifier is required");
21
+ }
22
+ const header = btoau(JSON.stringify(SUBSTITUTE_USER_HEADER));
23
+ const payload = btoau(JSON.stringify({ sub: identifier }));
24
+ return `${header}.${payload}.`;
25
+ }
26
+ function btoau(str) {
27
+ return btoa(str).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
28
+ }
29
+ //# sourceMappingURL=substituteUser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"substituteUser.js","sourceRoot":"","sources":["../../../src/jwt/substituteUser.ts"],"names":[],"mappings":";;AAeA,4DAOC;AAtBD,MAAM,sBAAsB,GAAG,EAAE,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;AAErE;;;;;;;;;;;;GAYG;AACH,SAAgB,wBAAwB,CAAC,UAAkB;IACzD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;IAC3D,OAAO,GAAG,MAAM,IAAI,OAAO,GAAG,CAAC;AACjC,CAAC;AAED,SAAS,KAAK,CAAC,GAAW;IACxB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAC7E,CAAC"}
@@ -1,8 +1,29 @@
1
1
  import { OAuthKeyring } from "../keyring.js";
2
2
  import type { JWTClaims } from "./signer.js";
3
+ export interface JWTVerifierOptions {
4
+ /**
5
+ * Issuer(s) this verifier will accept. The `iss` claim in a presented token
6
+ * must exactly match (string equality) one of these values. Tokens with any
7
+ * other issuer are rejected before any key lookup or network I/O runs.
8
+ */
9
+ issuers: string | readonly string[];
10
+ /**
11
+ * Audience(s) the token must be intended for. When configured, the token's
12
+ * `aud` claim must be present and contain at least one of these values.
13
+ * When omitted, audience is not validated.
14
+ */
15
+ audiences?: string | readonly string[];
16
+ /**
17
+ * Allowed JWT algorithms. Defaults to `["RS256"]`. The `alg` header of a
18
+ * presented token must be a member. `"none"` is always rejected. Values
19
+ * must be in the set the verifier actually implements (currently only
20
+ * `"RS256"`).
21
+ */
22
+ algorithms?: readonly string[];
23
+ }
3
24
  export declare class JWTVerifier {
4
25
  #private;
5
- constructor(keyring: OAuthKeyring);
26
+ constructor(keyring: OAuthKeyring, options: JWTVerifierOptions);
6
27
  verify(token: string): Promise<JWTClaims>;
7
28
  }
8
29
  //# sourceMappingURL=verifier.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"verifier.d.ts","sourceRoot":"","sources":["../../../src/jwt/verifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,qBAAa,WAAW;;gBAGV,OAAO,EAAE,YAAY;IAI3B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;CA2BhD"}
1
+ {"version":3,"file":"verifier.d.ts","sourceRoot":"","sources":["../../../src/jwt/verifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;IAEpC;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;IAEvC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC;AAUD,qBAAa,WAAW;;gBAMV,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,kBAAkB;IA+BxD,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;CA4FhD"}
@@ -13,27 +13,119 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
13
13
  var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
- var _JWTVerifier_keyring;
16
+ var _JWTVerifier_keyring, _JWTVerifier_issuers, _JWTVerifier_audiences, _JWTVerifier_algorithms;
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.JWTVerifier = void 0;
19
19
  const errors_js_1 = require("../errors.js");
20
20
  const base64url_js_1 = __importDefault(require("../base64url.js"));
21
+ // The single `crypto.subtle.verify` call in `verify()` is hardcoded to
22
+ // RSASSA-PKCS1-v1_5 + SHA-256, so the `algorithms` option is only meaningful
23
+ // as an allowlist that's a subset of what we actually implement. Used both
24
+ // as the default when the option is omitted and to validate user-supplied
25
+ // values at construction time.
26
+ const SUPPORTED_ALGORITHMS = ["RS256"];
27
+ const SUPPORTED_ALGORITHM_SET = new Set(SUPPORTED_ALGORITHMS);
21
28
  class JWTVerifier {
22
- constructor(keyring) {
29
+ constructor(keyring, options) {
23
30
  _JWTVerifier_keyring.set(this, void 0);
31
+ _JWTVerifier_issuers.set(this, void 0);
32
+ _JWTVerifier_audiences.set(this, void 0);
33
+ _JWTVerifier_algorithms.set(this, void 0);
34
+ const rawIssuers = typeof options?.issuers === "string" ? [options.issuers] : options?.issuers ?? [];
35
+ if (rawIssuers.length === 0) {
36
+ throw new Error("JWTVerifier requires at least one trusted issuer");
37
+ }
38
+ const rawAudiences = typeof options.audiences === "string"
39
+ ? [options.audiences]
40
+ : options.audiences ?? [];
41
+ const rawAlgorithms = options.algorithms ?? SUPPORTED_ALGORITHMS;
42
+ for (const alg of rawAlgorithms) {
43
+ if (!SUPPORTED_ALGORITHM_SET.has(alg)) {
44
+ throw new Error(`JWTVerifier does not implement signature verification for "${alg}". ` +
45
+ `Supported: ${SUPPORTED_ALGORITHMS.join(", ")}.`);
46
+ }
47
+ }
24
48
  __classPrivateFieldSet(this, _JWTVerifier_keyring, keyring, "f");
49
+ __classPrivateFieldSet(this, _JWTVerifier_issuers, new Set(rawIssuers), "f");
50
+ // An empty `audiences` list means "unconfigured" — matches the ergonomic
51
+ // intent of passing `audiences: []`. A non-empty list switches audience
52
+ // validation on; a missing `aud` fails closed.
53
+ __classPrivateFieldSet(this, _JWTVerifier_audiences, rawAudiences.length > 0 ? new Set(rawAudiences) : undefined, "f");
54
+ __classPrivateFieldSet(this, _JWTVerifier_algorithms, new Set(rawAlgorithms), "f");
25
55
  }
26
56
  async verify(token) {
27
- const [header, payload, signature, ...rest] = token.split('.');
28
- const jsonHeader = JSON.parse(autob(header));
29
- const jsonPayload = JSON.parse(autob(payload));
57
+ const parts = token.split(".");
58
+ if (parts.length !== 3) {
59
+ throw new errors_js_1.InvalidTokenError("Malformed JWT");
60
+ }
61
+ const [header, payload, signature] = parts;
62
+ let jsonHeader;
63
+ let jsonPayload;
64
+ try {
65
+ jsonHeader = JSON.parse(autob(header));
66
+ jsonPayload = JSON.parse(autob(payload));
67
+ }
68
+ catch {
69
+ throw new errors_js_1.InvalidTokenError("Malformed JWT");
70
+ }
71
+ // Algorithm allowlist. Reject "none" and anything outside the allowlist
72
+ // before any other work.
73
+ if (!jsonHeader.alg || jsonHeader.alg === "none" || !__classPrivateFieldGet(this, _JWTVerifier_algorithms, "f").has(jsonHeader.alg)) {
74
+ throw new errors_js_1.InvalidTokenError(`Unsupported JWT algorithm: ${jsonHeader.alg ?? "none"}`);
75
+ }
76
+ // Issuer allowlist. Rejected BEFORE any keyring call — guarantees a token
77
+ // with an attacker-controlled `iss` can't trigger discovery against an
78
+ // untrusted URL.
30
79
  if (!jsonPayload.iss) {
31
80
  throw new errors_js_1.InvalidTokenError("JWT missing issuer (iss) claim");
32
81
  }
82
+ if (!__classPrivateFieldGet(this, _JWTVerifier_issuers, "f").has(jsonPayload.iss)) {
83
+ throw new errors_js_1.InvalidTokenError("Untrusted issuer");
84
+ }
85
+ // Required claims per RFC 9068 § 2.2. Reject NaN / Infinity explicitly —
86
+ // `typeof NaN === "number"` passes the type check but would make every
87
+ // comparison below false (and with `exp: NaN` that means effectively no
88
+ // expiration).
89
+ if (!Number.isFinite(jsonPayload.exp)) {
90
+ throw new errors_js_1.InvalidTokenError("JWT missing expiration (exp) claim");
91
+ }
92
+ if (!jsonPayload.client_id) {
93
+ throw new errors_js_1.InvalidTokenError("JWT missing client_id claim");
94
+ }
95
+ // Time-based claims.
96
+ const now = Math.floor(Date.now() / 1000);
97
+ if (now > jsonPayload.exp) {
98
+ throw new errors_js_1.InvalidTokenError("Token expired");
99
+ }
100
+ if (jsonPayload.nbf !== undefined) {
101
+ if (!Number.isFinite(jsonPayload.nbf)) {
102
+ throw new errors_js_1.InvalidTokenError("JWT has invalid not-before (nbf) claim");
103
+ }
104
+ if (now < jsonPayload.nbf) {
105
+ throw new errors_js_1.InvalidTokenError("Token not yet valid");
106
+ }
107
+ }
108
+ // Audience check, if configured. Missing `aud` fails closed when audiences
109
+ // are required — matches RFC 8707 resource-indicator expectations.
110
+ if (__classPrivateFieldGet(this, _JWTVerifier_audiences, "f")) {
111
+ const aud = jsonPayload.aud;
112
+ if (aud === undefined) {
113
+ throw new errors_js_1.InvalidTokenError("JWT missing audience (aud) claim");
114
+ }
115
+ const audValues = Array.isArray(aud) ? aud : [aud];
116
+ const matched = audValues.some((a) => __classPrivateFieldGet(this, _JWTVerifier_audiences, "f").has(a));
117
+ if (!matched) {
118
+ throw new errors_js_1.InvalidTokenError("Audience mismatch");
119
+ }
120
+ }
121
+ // Only after all cheap policy checks do we touch the keyring.
122
+ if (!jsonHeader.kid) {
123
+ throw new errors_js_1.InvalidTokenError("JWT missing key id (kid) header");
124
+ }
33
125
  const key = await __classPrivateFieldGet(this, _JWTVerifier_keyring, "f").key(jsonPayload.iss, jsonHeader.kid);
34
126
  const verified = await crypto.subtle.verify({
35
- name: 'RSASSA-PKCS1-v1_5',
36
- hash: { name: 'SHA-256' },
127
+ name: "RSASSA-PKCS1-v1_5",
128
+ hash: { name: "SHA-256" },
37
129
  }, key, base64url_js_1.default.decode(signature), new TextEncoder().encode(`${header}.${payload}`));
38
130
  if (!verified) {
39
131
  throw new errors_js_1.InvalidTokenError("Invalid signature");
@@ -42,8 +134,8 @@ class JWTVerifier {
42
134
  }
43
135
  }
44
136
  exports.JWTVerifier = JWTVerifier;
45
- _JWTVerifier_keyring = new WeakMap();
137
+ _JWTVerifier_keyring = new WeakMap(), _JWTVerifier_issuers = new WeakMap(), _JWTVerifier_audiences = new WeakMap(), _JWTVerifier_algorithms = new WeakMap();
46
138
  function autob(data) {
47
- return atob(data.replace(/-/g, '+').replace(/_/g, '/'));
139
+ return atob(data.replace(/-/g, "+").replace(/_/g, "/"));
48
140
  }
49
141
  //# sourceMappingURL=verifier.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"verifier.js","sourceRoot":"","sources":["../../../src/jwt/verifier.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AACA,4CAAiD;AACjD,mEAAwC;AAGxC,MAAa,WAAW;IAGtB,YAAY,OAAqB;QAFjC,uCAAuB;QAGrB,uBAAA,IAAI,wBAAY,OAAO,MAAA,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa;QACxB,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAE/D,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7C,MAAM,WAAW,GAAc,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAE1D,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC;YACrB,MAAM,IAAI,6BAAiB,CAAC,gCAAgC,CAAC,CAAC;QAChE,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,uBAAA,IAAI,4BAAS,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC;QAErE,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CACzC;YACE,IAAI,EAAE,mBAAmB;YACzB,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;SAC1B,EACD,GAAG,EACH,sBAAS,CAAC,MAAM,CAAC,SAAS,CAAC,EAC3B,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,MAAM,IAAI,OAAO,EAAE,CAAC,CACjD,CAAC;QACF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,6BAAiB,CAAC,mBAAmB,CAAC,CAAC;QACnD,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;CACF;AAlCD,kCAkCC;;AAED,SAAS,KAAK,CAAC,IAAY;IACzB,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;AAC1D,CAAC"}
1
+ {"version":3,"file":"verifier.js","sourceRoot":"","sources":["../../../src/jwt/verifier.ts"],"names":[],"mappings":"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"}
@@ -22,5 +22,11 @@ export declare class JWKSOAuthKeyring implements OAuthKeyring {
22
22
  constructor(options?: JWKSOAuthKeyringOptions);
23
23
  key(issuer: string, kid: string): Promise<CryptoKey>;
24
24
  invalidate(issuer: string, kid: string): void;
25
+ /**
26
+ * Drops all cached keys, JWKS URI discoveries, and inflight resolutions.
27
+ * Use after a global key rotation when targeted `invalidate(issuer, kid)`
28
+ * is impractical. Subsequent `key()` calls re-discover and re-fetch.
29
+ */
30
+ clear(): void;
25
31
  }
26
32
  //# sourceMappingURL=keyring.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"keyring.d.ts","sourceRoot":"","sources":["../../src/keyring.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;CACrD;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;CAC7C;AAED,MAAM,WAAW,uBAAuB;IACtC,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAuDD,qBAAa,gBAAiB,YAAW,YAAY;;gBAWvC,OAAO,CAAC,EAAE,uBAAuB;IAMvC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAW1D,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;CA4H9C"}
1
+ {"version":3,"file":"keyring.d.ts","sourceRoot":"","sources":["../../src/keyring.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;CACrD;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;CAC7C;AAED,MAAM,WAAW,uBAAuB;IACtC,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAuDD,qBAAa,gBAAiB,YAAW,YAAY;;gBAWvC,OAAO,CAAC,EAAE,uBAAuB;IAMvC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAW1D,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAQ7C;;;;OAIG;IACH,KAAK,IAAI,IAAI;CA2Hd"}
@@ -79,6 +79,17 @@ class JWKSOAuthKeyring {
79
79
  __classPrivateFieldGet(this, _JWKSOAuthKeyring_discoveryCache, "f").delete(issuer);
80
80
  __classPrivateFieldGet(this, _JWKSOAuthKeyring_discoveryInflight, "f").delete(issuer);
81
81
  }
82
+ /**
83
+ * Drops all cached keys, JWKS URI discoveries, and inflight resolutions.
84
+ * Use after a global key rotation when targeted `invalidate(issuer, kid)`
85
+ * is impractical. Subsequent `key()` calls re-discover and re-fetch.
86
+ */
87
+ clear() {
88
+ __classPrivateFieldGet(this, _JWKSOAuthKeyring_keyCache, "f").clear();
89
+ __classPrivateFieldGet(this, _JWKSOAuthKeyring_keyInflight, "f").clear();
90
+ __classPrivateFieldGet(this, _JWKSOAuthKeyring_discoveryCache, "f").clear();
91
+ __classPrivateFieldGet(this, _JWKSOAuthKeyring_discoveryInflight, "f").clear();
92
+ }
82
93
  }
83
94
  exports.JWKSOAuthKeyring = JWKSOAuthKeyring;
84
95
  _JWKSOAuthKeyring_keyTtlMs = new WeakMap(), _JWKSOAuthKeyring_discoveryTtlMs = new WeakMap(), _JWKSOAuthKeyring_fetchTimeoutMs = new WeakMap(), _JWKSOAuthKeyring_discoveryCache = new WeakMap(), _JWKSOAuthKeyring_keyCache = new WeakMap(), _JWKSOAuthKeyring_discoveryInflight = new WeakMap(), _JWKSOAuthKeyring_keyInflight = new WeakMap(), _JWKSOAuthKeyring_instances = new WeakSet(), _JWKSOAuthKeyring_resolveJwksUri =