@keycardai/oauth 0.5.0 → 0.7.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 (51) hide show
  1. package/LICENSE +5 -17
  2. package/README.md +45 -0
  3. package/dist/cjs/index.d.ts +2 -0
  4. package/dist/cjs/index.d.ts.map +1 -1
  5. package/dist/cjs/index.js +7 -1
  6. package/dist/cjs/index.js.map +1 -1
  7. package/dist/cjs/pkce.d.ts +64 -0
  8. package/dist/cjs/pkce.d.ts.map +1 -0
  9. package/dist/cjs/pkce.js +249 -0
  10. package/dist/cjs/pkce.js.map +1 -0
  11. package/dist/cjs/server/eksWorkloadIdentity.d.ts +22 -0
  12. package/dist/cjs/server/eksWorkloadIdentity.d.ts.map +1 -0
  13. package/dist/cjs/server/eksWorkloadIdentity.js +117 -0
  14. package/dist/cjs/server/eksWorkloadIdentity.js.map +1 -0
  15. package/dist/cjs/server/index.d.ts +6 -0
  16. package/dist/cjs/server/index.d.ts.map +1 -1
  17. package/dist/cjs/server/index.js +8 -1
  18. package/dist/cjs/server/index.js.map +1 -1
  19. package/dist/cjs/server/privateKey.d.ts +47 -0
  20. package/dist/cjs/server/privateKey.d.ts.map +1 -0
  21. package/dist/cjs/server/privateKey.js +233 -0
  22. package/dist/cjs/server/privateKey.js.map +1 -0
  23. package/dist/cjs/server/webIdentity.d.ts +37 -0
  24. package/dist/cjs/server/webIdentity.d.ts.map +1 -0
  25. package/dist/cjs/server/webIdentity.js +75 -0
  26. package/dist/cjs/server/webIdentity.js.map +1 -0
  27. package/dist/esm/index.d.ts +2 -0
  28. package/dist/esm/index.d.ts.map +1 -1
  29. package/dist/esm/index.js +1 -0
  30. package/dist/esm/index.js.map +1 -1
  31. package/dist/esm/pkce.d.ts +64 -0
  32. package/dist/esm/pkce.d.ts.map +1 -0
  33. package/dist/esm/pkce.js +206 -0
  34. package/dist/esm/pkce.js.map +1 -0
  35. package/dist/esm/server/eksWorkloadIdentity.d.ts +22 -0
  36. package/dist/esm/server/eksWorkloadIdentity.d.ts.map +1 -0
  37. package/dist/esm/server/eksWorkloadIdentity.js +80 -0
  38. package/dist/esm/server/eksWorkloadIdentity.js.map +1 -0
  39. package/dist/esm/server/index.d.ts +6 -0
  40. package/dist/esm/server/index.d.ts.map +1 -1
  41. package/dist/esm/server/index.js +3 -0
  42. package/dist/esm/server/index.js.map +1 -1
  43. package/dist/esm/server/privateKey.d.ts +47 -0
  44. package/dist/esm/server/privateKey.d.ts.map +1 -0
  45. package/dist/esm/server/privateKey.js +195 -0
  46. package/dist/esm/server/privateKey.js.map +1 -0
  47. package/dist/esm/server/webIdentity.d.ts +37 -0
  48. package/dist/esm/server/webIdentity.d.ts.map +1 -0
  49. package/dist/esm/server/webIdentity.js +71 -0
  50. package/dist/esm/server/webIdentity.js.map +1 -0
  51. package/package.json +7 -1
package/LICENSE CHANGED
@@ -1,21 +1,9 @@
1
- MIT License
1
+ MIT LICENSE
2
2
 
3
- Copyright (c) 2024 Keycard
3
+ Copyright © 2026 Keycard Labs, inc.
4
4
 
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11
6
 
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14
8
 
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -157,6 +157,40 @@ returns the issued client credentials. Throws `OAuthError` on RFC 6749 §5.2
157
157
  error responses, a plain `Error` on missing `registration_endpoint` or
158
158
  non-OAuth HTTP failures.
159
159
 
160
+ ### PKCE (RFC 7636)
161
+
162
+ ```typescript
163
+ import {
164
+ generateCodeVerifier,
165
+ generateCodeChallenge,
166
+ generatePkcePair,
167
+ exchangeAuthorizationCode,
168
+ authenticate,
169
+ } from "@keycardai/oauth/pkce";
170
+
171
+ // Generate primitives for a custom auth-code flow
172
+ const { codeVerifier, codeChallenge } = await generatePkcePair();
173
+
174
+ // Exchange code received at the redirect URI
175
+ const tokens = await exchangeAuthorizationCode(
176
+ "https://your-zone.keycard.cloud",
177
+ authorizationCode,
178
+ { codeVerifier, redirectUri: "https://app.example.com/callback", clientId: "my-client" },
179
+ );
180
+
181
+ // Or let authenticate() drive the full flow (Node.js only)
182
+ const tokens2 = await authenticate("https://your-zone.keycard.cloud", {
183
+ clientId: "my-client",
184
+ scopes: ["read", "write"],
185
+ });
186
+ ```
187
+
188
+ `generateCodeVerifier` and `generateCodeChallenge` use the global `crypto` API and
189
+ are runtime-agnostic (Node.js, Cloudflare Workers, browser). `authenticate()` drives
190
+ the full browser-launch and loopback-callback flow and **requires Node.js** — it uses
191
+ dynamic imports of `node:http` and `node:child_process` and will throw a runtime error
192
+ if called in a non-Node environment.
193
+
160
194
  ## API Overview
161
195
 
162
196
  ### JWKS Key Management
@@ -185,6 +219,17 @@ non-OAuth HTTP failures.
185
219
  | `buildSubstituteUserToken` | `@keycardai/oauth/jwt/substituteUser` | Builds the unsigned subject JWT for impersonation calls |
186
220
  | `registerClient` | `@keycardai/oauth/registration` | RFC 7591 dynamic client registration with auto-discovery |
187
221
 
222
+ ### PKCE (RFC 7636)
223
+
224
+ | Export | Import Path | Description |
225
+ |---|---|---|
226
+ | `generateCodeVerifier` | `@keycardai/oauth/pkce` | Generates a 43-char random code verifier (RFC 7636 §4.1) |
227
+ | `generateCodeChallenge` | `@keycardai/oauth/pkce` | Computes S256 or plain code challenge from a verifier (RFC 7636 §4.2) |
228
+ | `generatePkcePair` | `@keycardai/oauth/pkce` | Convenience: generates verifier + challenge in one call |
229
+ | `exchangeAuthorizationCode` | `@keycardai/oauth/pkce` | Exchanges an authorization code with code_verifier at the token endpoint |
230
+ | `authenticate` | `@keycardai/oauth/pkce` | Full browser-launch and loopback-callback flow. **Node.js only** |
231
+ | `Pkce` (type) | `@keycardai/oauth/pkce` | `{ codeVerifier, codeChallenge, codeChallengeMethod }` |
232
+
188
233
  ### Server-tier Primitives
189
234
 
190
235
  | Export | Import Path | Description |
@@ -15,4 +15,6 @@ export { registerClient } from "./registration.js";
15
15
  export type { ClientRegistrationRequest, ClientRegistrationResponse, RegisterClientOptions, } from "./registration.js";
16
16
  export { AccessContext, TokenVerifier, ClientSecret } from "./server/index.js";
17
17
  export type { ErrorDetail, AccessContextStatus, AccessToken, TokenVerifierOptions, ClientSecretCredentials, } from "./server/index.js";
18
+ export { generateCodeVerifier, generateCodeChallenge, generatePkcePair, exchangeAuthorizationCode, authenticate, } from "./pkce.js";
19
+ export type { Pkce, ExchangeAuthorizationCodeOptions, AuthenticateOptions, } from "./pkce.js";
18
20
  //# 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,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,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,YAAY,EACV,yBAAyB,EACzB,0BAA0B,EAC1B,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,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"}
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,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,YAAY,EACV,yBAAyB,EACzB,0BAA0B,EAC1B,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,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;AAC3B,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,gBAAgB,EAChB,yBAAyB,EACzB,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,IAAI,EACJ,gCAAgC,EAChC,mBAAmB,GACpB,MAAM,WAAW,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.ClientSecret = exports.TokenVerifier = exports.AccessContext = exports.registerClient = 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;
6
+ exports.authenticate = exports.exchangeAuthorizationCode = exports.generatePkcePair = exports.generateCodeChallenge = exports.generateCodeVerifier = exports.ClientSecret = exports.TokenVerifier = exports.AccessContext = exports.registerClient = 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");
@@ -34,4 +34,10 @@ var index_js_1 = require("./server/index.js");
34
34
  Object.defineProperty(exports, "AccessContext", { enumerable: true, get: function () { return index_js_1.AccessContext; } });
35
35
  Object.defineProperty(exports, "TokenVerifier", { enumerable: true, get: function () { return index_js_1.TokenVerifier; } });
36
36
  Object.defineProperty(exports, "ClientSecret", { enumerable: true, get: function () { return index_js_1.ClientSecret; } });
37
+ var pkce_js_1 = require("./pkce.js");
38
+ Object.defineProperty(exports, "generateCodeVerifier", { enumerable: true, get: function () { return pkce_js_1.generateCodeVerifier; } });
39
+ Object.defineProperty(exports, "generateCodeChallenge", { enumerable: true, get: function () { return pkce_js_1.generateCodeChallenge; } });
40
+ Object.defineProperty(exports, "generatePkcePair", { enumerable: true, get: function () { return pkce_js_1.generatePkcePair; } });
41
+ Object.defineProperty(exports, "exchangeAuthorizationCode", { enumerable: true, get: function () { return pkce_js_1.exchangeAuthorizationCode; } });
42
+ Object.defineProperty(exports, "authenticate", { enumerable: true, get: function () { return pkce_js_1.authenticate; } });
37
43
  //# 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,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,qDAAmD;AAA1C,iHAAA,cAAc,OAAA;AAMvB,8CAA+E;AAAtE,yGAAA,aAAa,OAAA;AAAE,yGAAA,aAAa,OAAA;AAAE,wGAAA,YAAY,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,qDAAmD;AAA1C,iHAAA,cAAc,OAAA;AAMvB,8CAA+E;AAAtE,yGAAA,aAAa,OAAA;AAAE,yGAAA,aAAa,OAAA;AAAE,wGAAA,YAAY,OAAA;AAQnD,qCAMmB;AALjB,+GAAA,oBAAoB,OAAA;AACpB,gHAAA,qBAAqB,OAAA;AACrB,2GAAA,gBAAgB,OAAA;AAChB,oHAAA,yBAAyB,OAAA;AACzB,uGAAA,YAAY,OAAA"}
@@ -0,0 +1,64 @@
1
+ import type { TokenResponse } from "./tokenExchange.js";
2
+ export interface Pkce {
3
+ codeVerifier: string;
4
+ codeChallenge: string;
5
+ codeChallengeMethod: "S256" | "plain";
6
+ }
7
+ /**
8
+ * Generate a cryptographically random PKCE code verifier (RFC 7636 §4.1).
9
+ *
10
+ * Returns a 43-character base64url string (32 random bytes). Runtime-agnostic:
11
+ * uses the global `crypto.getRandomValues` which is available in Node 19+,
12
+ * Cloudflare Workers, and browsers.
13
+ */
14
+ export declare function generateCodeVerifier(): string;
15
+ /**
16
+ * Derive a PKCE code challenge from a code verifier (RFC 7636 §4.2).
17
+ *
18
+ * S256 (default): `BASE64URL(SHA-256(ASCII(code_verifier)))`
19
+ * plain: returns the verifier unchanged (not recommended; use only when
20
+ * the AS does not support S256).
21
+ */
22
+ export declare function generateCodeChallenge(verifier: string, method?: "S256" | "plain"): Promise<string>;
23
+ /**
24
+ * Generate a PKCE pair (verifier + challenge) in one call.
25
+ */
26
+ export declare function generatePkcePair(method?: "S256" | "plain"): Promise<Pkce>;
27
+ export interface ExchangeAuthorizationCodeOptions {
28
+ codeVerifier: string;
29
+ redirectUri: string;
30
+ clientId?: string;
31
+ clientSecret?: string;
32
+ signal?: AbortSignal;
33
+ }
34
+ /**
35
+ * Exchange an authorization code for tokens (RFC 6749 §4.1.3 + RFC 7636).
36
+ *
37
+ * Discovers `token_endpoint` from the AS metadata, then POSTs
38
+ * `grant_type=authorization_code` with the code verifier.
39
+ */
40
+ export declare function exchangeAuthorizationCode(issuerUrl: string, code: string, options: ExchangeAuthorizationCodeOptions): Promise<TokenResponse>;
41
+ export interface AuthenticateOptions {
42
+ clientId: string;
43
+ /** Default: "http://localhost:{port}/callback" */
44
+ redirectUri?: string;
45
+ /** Default: 8080 */
46
+ port?: number;
47
+ scopes?: readonly string[];
48
+ clientSecret?: string;
49
+ /** Default: 60_000 ms */
50
+ timeoutMs?: number;
51
+ }
52
+ /**
53
+ * Full authorization-code-with-PKCE flow for local/CLI contexts.
54
+ *
55
+ * Generates a PKCE pair, builds the authorization URL, opens the user's
56
+ * browser, starts a local loopback HTTP server to receive the redirect,
57
+ * and exchanges the authorization code for tokens.
58
+ *
59
+ * **Requires Node.js.** Uses `node:http` and `node:child_process` via
60
+ * dynamic import. Importing this module is safe in any runtime; only
61
+ * *calling* `authenticate()` requires Node.js.
62
+ */
63
+ export declare function authenticate(issuerUrl: string, options: AuthenticateOptions): Promise<TokenResponse>;
64
+ //# sourceMappingURL=pkce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../src/pkce.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAMxD,MAAM,WAAW,IAAI;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,GAAG,OAAO,CAAC;CACvC;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAI7C;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAM,GAAG,OAAgB,GAChC,OAAO,CAAC,MAAM,CAAC,CASjB;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,GAAE,MAAM,GAAG,OAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAIvF;AAMD,MAAM,WAAW,gCAAgC;IAC/C,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC7C,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,gCAAgC,GACxC,OAAO,CAAC,aAAa,CAAC,CAyExB;AAMD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC,CAkCxB"}
@@ -0,0 +1,249 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.generateCodeVerifier = generateCodeVerifier;
40
+ exports.generateCodeChallenge = generateCodeChallenge;
41
+ exports.generatePkcePair = generatePkcePair;
42
+ exports.exchangeAuthorizationCode = exchangeAuthorizationCode;
43
+ exports.authenticate = authenticate;
44
+ const base64url_js_1 = __importDefault(require("./base64url.js"));
45
+ const discovery_js_1 = require("./discovery.js");
46
+ const errors_js_1 = require("./errors.js");
47
+ /**
48
+ * Generate a cryptographically random PKCE code verifier (RFC 7636 §4.1).
49
+ *
50
+ * Returns a 43-character base64url string (32 random bytes). Runtime-agnostic:
51
+ * uses the global `crypto.getRandomValues` which is available in Node 19+,
52
+ * Cloudflare Workers, and browsers.
53
+ */
54
+ function generateCodeVerifier() {
55
+ const bytes = new Uint8Array(32);
56
+ crypto.getRandomValues(bytes);
57
+ return base64url_js_1.default.encode(bytes.buffer);
58
+ }
59
+ /**
60
+ * Derive a PKCE code challenge from a code verifier (RFC 7636 §4.2).
61
+ *
62
+ * S256 (default): `BASE64URL(SHA-256(ASCII(code_verifier)))`
63
+ * plain: returns the verifier unchanged (not recommended; use only when
64
+ * the AS does not support S256).
65
+ */
66
+ async function generateCodeChallenge(verifier, method = "S256") {
67
+ if (method === "plain") {
68
+ return verifier;
69
+ }
70
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier));
71
+ return base64url_js_1.default.encode(digest);
72
+ }
73
+ /**
74
+ * Generate a PKCE pair (verifier + challenge) in one call.
75
+ */
76
+ async function generatePkcePair(method = "S256") {
77
+ const codeVerifier = generateCodeVerifier();
78
+ const codeChallenge = await generateCodeChallenge(codeVerifier, method);
79
+ return { codeVerifier, codeChallenge, codeChallengeMethod: method };
80
+ }
81
+ /**
82
+ * Exchange an authorization code for tokens (RFC 6749 §4.1.3 + RFC 7636).
83
+ *
84
+ * Discovers `token_endpoint` from the AS metadata, then POSTs
85
+ * `grant_type=authorization_code` with the code verifier.
86
+ */
87
+ async function exchangeAuthorizationCode(issuerUrl, code, options) {
88
+ const metadata = await (0, discovery_js_1.fetchAuthorizationServerMetadata)(issuerUrl, {
89
+ signal: options.signal,
90
+ });
91
+ if (!metadata.token_endpoint) {
92
+ throw new Error(`Authorization server "${issuerUrl}" does not advertise a token_endpoint`);
93
+ }
94
+ const params = new URLSearchParams();
95
+ params.set("grant_type", "authorization_code");
96
+ params.set("code", code);
97
+ params.set("code_verifier", options.codeVerifier);
98
+ params.set("redirect_uri", options.redirectUri);
99
+ if (options.clientId)
100
+ params.set("client_id", options.clientId);
101
+ const headers = {
102
+ "Content-Type": "application/x-www-form-urlencoded",
103
+ };
104
+ if (options.clientId && options.clientSecret) {
105
+ headers["Authorization"] = `Basic ${btoa(`${options.clientId}:${options.clientSecret}`)}`;
106
+ params.delete("client_id");
107
+ }
108
+ const response = await fetch(metadata.token_endpoint, {
109
+ method: "POST",
110
+ headers,
111
+ body: params.toString(),
112
+ signal: options.signal,
113
+ });
114
+ if (!response.ok) {
115
+ let errorBody = null;
116
+ try {
117
+ const json = await response.json();
118
+ if (json && typeof json === "object" && !Array.isArray(json)) {
119
+ errorBody = json;
120
+ }
121
+ }
122
+ catch {
123
+ // non-JSON error body — fall through to generic error
124
+ }
125
+ if (errorBody && typeof errorBody.error === "string") {
126
+ const description = typeof errorBody.error_description === "string"
127
+ ? errorBody.error_description
128
+ : errorBody.error;
129
+ const errorUri = typeof errorBody.error_uri === "string" ? errorBody.error_uri : undefined;
130
+ throw new errors_js_1.OAuthError(errorBody.error, description, errorUri);
131
+ }
132
+ throw new Error(`Authorization code exchange failed (HTTP ${response.status})`);
133
+ }
134
+ const json = await response.json();
135
+ if (!json || typeof json !== "object" || Array.isArray(json)) {
136
+ throw new Error("Token endpoint response is not a valid JSON object");
137
+ }
138
+ const body = json;
139
+ const accessToken = body.access_token;
140
+ if (typeof accessToken !== "string" || !accessToken) {
141
+ throw new Error("Token endpoint response missing access_token");
142
+ }
143
+ const tokenResponse = {
144
+ accessToken,
145
+ tokenType: typeof body.token_type === "string" ? body.token_type : "bearer",
146
+ };
147
+ if (typeof body.expires_in === "number")
148
+ tokenResponse.expiresIn = body.expires_in;
149
+ if (typeof body.refresh_token === "string")
150
+ tokenResponse.refreshToken = body.refresh_token;
151
+ if (typeof body.scope === "string") {
152
+ tokenResponse.scope = body.scope.split(" ").filter(Boolean);
153
+ }
154
+ return tokenResponse;
155
+ }
156
+ /**
157
+ * Full authorization-code-with-PKCE flow for local/CLI contexts.
158
+ *
159
+ * Generates a PKCE pair, builds the authorization URL, opens the user's
160
+ * browser, starts a local loopback HTTP server to receive the redirect,
161
+ * and exchanges the authorization code for tokens.
162
+ *
163
+ * **Requires Node.js.** Uses `node:http` and `node:child_process` via
164
+ * dynamic import. Importing this module is safe in any runtime; only
165
+ * *calling* `authenticate()` requires Node.js.
166
+ */
167
+ async function authenticate(issuerUrl, options) {
168
+ const port = options.port ?? 8080;
169
+ const redirectUri = options.redirectUri ?? `http://localhost:${port}/callback`;
170
+ const timeoutMs = options.timeoutMs ?? 60_000;
171
+ const { codeVerifier, codeChallenge } = await generatePkcePair("S256");
172
+ const metadata = await (0, discovery_js_1.fetchAuthorizationServerMetadata)(issuerUrl);
173
+ if (!metadata.authorization_endpoint) {
174
+ throw new Error(`Authorization server "${issuerUrl}" does not advertise an authorization_endpoint`);
175
+ }
176
+ const authUrl = new URL(metadata.authorization_endpoint);
177
+ authUrl.searchParams.set("response_type", "code");
178
+ authUrl.searchParams.set("client_id", options.clientId);
179
+ authUrl.searchParams.set("redirect_uri", redirectUri);
180
+ authUrl.searchParams.set("code_challenge", codeChallenge);
181
+ authUrl.searchParams.set("code_challenge_method", "S256");
182
+ if (options.scopes && options.scopes.length > 0) {
183
+ authUrl.searchParams.set("scope", options.scopes.join(" "));
184
+ }
185
+ await openBrowser(authUrl.toString());
186
+ const code = await waitForCode(port, redirectUri, timeoutMs);
187
+ return exchangeAuthorizationCode(issuerUrl, code, {
188
+ codeVerifier,
189
+ redirectUri,
190
+ clientId: options.clientId,
191
+ clientSecret: options.clientSecret,
192
+ });
193
+ }
194
+ async function openBrowser(url) {
195
+ const { execFile } = await Promise.resolve().then(() => __importStar(require("node:child_process")));
196
+ if (process.platform === "darwin") {
197
+ execFile("open", [url]);
198
+ }
199
+ else if (process.platform === "win32") {
200
+ // `start` is a cmd.exe built-in, not a standalone executable.
201
+ execFile("cmd", ["/c", "start", "", url]);
202
+ }
203
+ else {
204
+ execFile("xdg-open", [url]);
205
+ }
206
+ }
207
+ async function waitForCode(port, redirectUri, timeoutMs) {
208
+ // Import before entering the Promise constructor to avoid the async-executor
209
+ // anti-pattern: if the dynamic import throws, the rejection propagates through
210
+ // this async function rather than escaping an async Promise constructor.
211
+ const { createServer } = await Promise.resolve().then(() => __importStar(require("node:http")));
212
+ return new Promise((resolve, reject) => {
213
+ const timer = setTimeout(() => {
214
+ server.close();
215
+ reject(new Error(`PKCE authentication timed out after ${timeoutMs}ms`));
216
+ }, timeoutMs);
217
+ const server = createServer((req, res) => {
218
+ try {
219
+ const reqUrl = new URL(req.url ?? "/", redirectUri);
220
+ const code = reqUrl.searchParams.get("code");
221
+ const error = reqUrl.searchParams.get("error");
222
+ res.writeHead(200, { "Content-Type": "text/html" });
223
+ res.end("<html><body><p>Authentication complete. You can close this tab.</p></body></html>");
224
+ server.close();
225
+ clearTimeout(timer);
226
+ if (error) {
227
+ reject(new errors_js_1.OAuthError(error, reqUrl.searchParams.get("error_description") ?? error));
228
+ }
229
+ else if (code) {
230
+ resolve(code);
231
+ }
232
+ else {
233
+ reject(new Error("No authorization code in redirect"));
234
+ }
235
+ }
236
+ catch (e) {
237
+ server.close();
238
+ clearTimeout(timer);
239
+ reject(e);
240
+ }
241
+ });
242
+ server.listen(port, "localhost");
243
+ server.on("error", (err) => {
244
+ clearTimeout(timer);
245
+ reject(new Error(`Failed to start loopback server on port ${port}: ${err.message}`));
246
+ });
247
+ });
248
+ }
249
+ //# sourceMappingURL=pkce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../src/pkce.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { ApplicationCredential } from "../credentials.js";
2
+ import type { TokenExchangeRequest } from "../tokenExchange.js";
3
+ export interface EKSWorkloadIdentityOptions {
4
+ tokenFilePath?: string;
5
+ envVarName?: string;
6
+ }
7
+ /**
8
+ * EKS pod identity credential provider. Reads the workload identity token
9
+ * from the mounted file path (resolved from the standard EKS environment
10
+ * variables or the explicit `tokenFilePath` option) and uses it as a
11
+ * client assertion in RFC 8693 token exchange requests.
12
+ *
13
+ * **Requires Node.js.** Reads the token file synchronously from the
14
+ * filesystem at construction and exchange time.
15
+ */
16
+ export declare class EKSWorkloadIdentity implements ApplicationCredential {
17
+ #private;
18
+ constructor(options?: EKSWorkloadIdentityOptions);
19
+ getAuth(): null;
20
+ prepareTokenExchangeRequest(subjectToken: string, resource: string): Promise<TokenExchangeRequest>;
21
+ }
22
+ //# sourceMappingURL=eksWorkloadIdentity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eksWorkloadIdentity.d.ts","sourceRoot":"","sources":["../../../src/server/eksWorkloadIdentity.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAQhE,MAAM,WAAW,0BAA0B;IACzC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,YAAW,qBAAqB;;gBAGnD,OAAO,CAAC,EAAE,0BAA0B;IAmBhD,OAAO,IAAI,IAAI;IAIT,2BAA2B,CAC/B,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,oBAAoB,CAAC;CA+BjC"}
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
36
+ if (kind === "m") throw new TypeError("Private method is not writable");
37
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
38
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
39
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
40
+ };
41
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
42
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
43
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
44
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
45
+ };
46
+ var _EKSWorkloadIdentity_instances, _EKSWorkloadIdentity_tokenFilePath, _EKSWorkloadIdentity_validateTokenFile, _EKSWorkloadIdentity_readToken;
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.EKSWorkloadIdentity = void 0;
49
+ const fs = __importStar(require("node:fs"));
50
+ const DEFAULT_EKS_ENV_VARS = [
51
+ "KEYCARD_EKS_WORKLOAD_IDENTITY_TOKEN_FILE",
52
+ "AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE",
53
+ "AWS_WEB_IDENTITY_TOKEN_FILE",
54
+ ];
55
+ /**
56
+ * EKS pod identity credential provider. Reads the workload identity token
57
+ * from the mounted file path (resolved from the standard EKS environment
58
+ * variables or the explicit `tokenFilePath` option) and uses it as a
59
+ * client assertion in RFC 8693 token exchange requests.
60
+ *
61
+ * **Requires Node.js.** Reads the token file synchronously from the
62
+ * filesystem at construction and exchange time.
63
+ */
64
+ class EKSWorkloadIdentity {
65
+ constructor(options) {
66
+ _EKSWorkloadIdentity_instances.add(this);
67
+ _EKSWorkloadIdentity_tokenFilePath.set(this, void 0);
68
+ if (options?.tokenFilePath) {
69
+ __classPrivateFieldSet(this, _EKSWorkloadIdentity_tokenFilePath, options.tokenFilePath, "f");
70
+ }
71
+ else {
72
+ const envNames = options?.envVarName
73
+ ? [options.envVarName, ...DEFAULT_EKS_ENV_VARS]
74
+ : DEFAULT_EKS_ENV_VARS;
75
+ const found = envNames.find((name) => process.env[name]);
76
+ if (!found || !process.env[found]) {
77
+ throw new Error(`EKSWorkloadIdentity: could not find token file path in environment variables. ` +
78
+ `Checked: ${envNames.join(", ")}`);
79
+ }
80
+ __classPrivateFieldSet(this, _EKSWorkloadIdentity_tokenFilePath, process.env[found], "f");
81
+ }
82
+ __classPrivateFieldGet(this, _EKSWorkloadIdentity_instances, "m", _EKSWorkloadIdentity_validateTokenFile).call(this);
83
+ }
84
+ getAuth() {
85
+ return null;
86
+ }
87
+ async prepareTokenExchangeRequest(subjectToken, resource) {
88
+ return {
89
+ subjectToken,
90
+ resource,
91
+ subjectTokenType: "urn:ietf:params:oauth:token-type:access_token",
92
+ clientAssertionType: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
93
+ clientAssertion: __classPrivateFieldGet(this, _EKSWorkloadIdentity_instances, "m", _EKSWorkloadIdentity_readToken).call(this),
94
+ };
95
+ }
96
+ }
97
+ exports.EKSWorkloadIdentity = EKSWorkloadIdentity;
98
+ _EKSWorkloadIdentity_tokenFilePath = new WeakMap(), _EKSWorkloadIdentity_instances = new WeakSet(), _EKSWorkloadIdentity_validateTokenFile = function _EKSWorkloadIdentity_validateTokenFile() {
99
+ try {
100
+ const token = fs.readFileSync(__classPrivateFieldGet(this, _EKSWorkloadIdentity_tokenFilePath, "f"), "utf-8").trim();
101
+ if (!token) {
102
+ throw new Error(`EKSWorkloadIdentity: token file is empty: ${__classPrivateFieldGet(this, _EKSWorkloadIdentity_tokenFilePath, "f")}`);
103
+ }
104
+ }
105
+ catch (error) {
106
+ if (error instanceof Error && error.message.startsWith("EKSWorkloadIdentity:"))
107
+ throw error;
108
+ throw new Error(`EKSWorkloadIdentity: error reading token file "${__classPrivateFieldGet(this, _EKSWorkloadIdentity_tokenFilePath, "f")}": ${error}`);
109
+ }
110
+ }, _EKSWorkloadIdentity_readToken = function _EKSWorkloadIdentity_readToken() {
111
+ const token = fs.readFileSync(__classPrivateFieldGet(this, _EKSWorkloadIdentity_tokenFilePath, "f"), "utf-8").trim();
112
+ if (!token) {
113
+ throw new Error(`EKSWorkloadIdentity: token file is empty: ${__classPrivateFieldGet(this, _EKSWorkloadIdentity_tokenFilePath, "f")}`);
114
+ }
115
+ return token;
116
+ };
117
+ //# sourceMappingURL=eksWorkloadIdentity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eksWorkloadIdentity.js","sourceRoot":"","sources":["../../../src/server/eksWorkloadIdentity.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,4CAA8B;AAI9B,MAAM,oBAAoB,GAAG;IAC3B,0CAA0C;IAC1C,wCAAwC;IACxC,6BAA6B;CAC9B,CAAC;AAOF;;;;;;;;GAQG;AACH,MAAa,mBAAmB;IAG9B,YAAY,OAAoC;;QAFhD,qDAAuB;QAGrB,IAAI,OAAO,EAAE,aAAa,EAAE,CAAC;YAC3B,uBAAA,IAAI,sCAAkB,OAAO,CAAC,aAAa,MAAA,CAAC;QAC9C,CAAC;aAAM,CAAC;YACN,MAAM,QAAQ,GAAG,OAAO,EAAE,UAAU;gBAClC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,oBAAoB,CAAC;gBAC/C,CAAC,CAAC,oBAAoB,CAAC;YACzB,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;YACzD,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBAClC,MAAM,IAAI,KAAK,CACb,gFAAgF;oBAChF,YAAY,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAClC,CAAC;YACJ,CAAC;YACD,uBAAA,IAAI,sCAAkB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAE,MAAA,CAAC;QAC5C,CAAC;QACD,uBAAA,IAAI,8EAAmB,MAAvB,IAAI,CAAqB,CAAC;IAC5B,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,2BAA2B,CAC/B,YAAoB,EACpB,QAAgB;QAEhB,OAAO;YACL,YAAY;YACZ,QAAQ;YACR,gBAAgB,EAAE,+CAA+C;YACjE,mBAAmB,EAAE,wDAAwD;YAC7E,eAAe,EAAE,uBAAA,IAAI,sEAAW,MAAf,IAAI,CAAa;SACnC,CAAC;IACJ,CAAC;CAuBF;AA5DD,kDA4DC;;IApBG,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,uBAAA,IAAI,0CAAe,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QACnE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,6CAA6C,uBAAA,IAAI,0CAAe,EAAE,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,sBAAsB,CAAC;YAAE,MAAM,KAAK,CAAC;QAC5F,MAAM,IAAI,KAAK,CACb,kDAAkD,uBAAA,IAAI,0CAAe,MAAM,KAAK,EAAE,CACnF,CAAC;IACJ,CAAC;AACH,CAAC;IAGC,MAAM,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,uBAAA,IAAI,0CAAe,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACnE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,6CAA6C,uBAAA,IAAI,0CAAe,EAAE,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -5,4 +5,10 @@ export { TokenVerifier } from "./tokenVerifier.js";
5
5
  export type { TokenVerifierOptions } from "./tokenVerifier.js";
6
6
  export { ClientSecret } from "./clientSecret.js";
7
7
  export type { ClientSecretCredentials } from "./clientSecret.js";
8
+ export { FilePrivateKeyStorage, PrivateKeyManager } from "./privateKey.js";
9
+ export type { PrivateKeyStorage, JsonWebKey } from "./privateKey.js";
10
+ export { WebIdentity } from "./webIdentity.js";
11
+ export type { WebIdentityOptions } from "./webIdentity.js";
12
+ export { EKSWorkloadIdentity } from "./eksWorkloadIdentity.js";
13
+ export type { EKSWorkloadIdentityOptions } from "./eksWorkloadIdentity.js";
8
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC3E,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC3E,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC3E,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC"}