@keycardai/oauth 0.4.1 → 0.6.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.
package/README.md CHANGED
@@ -136,6 +136,61 @@ expired token, missing scope, audience mismatch) return `null`; callers map that
136
136
  to an HTTP 401. `verifyTokenForZone(token, zoneId)` enables per-zone validation
137
137
  when the verifier is constructed with `enableMultiZone: true`.
138
138
 
139
+ ### Dynamic Client Registration (RFC 7591)
140
+
141
+ ```typescript
142
+ import { registerClient } from "@keycardai/oauth/registration";
143
+
144
+ const response = await registerClient("https://your-zone.keycard.cloud", {
145
+ clientName: "My Service",
146
+ redirectUris: ["https://app.example.com/callback"],
147
+ grantTypes: ["client_credentials"],
148
+ scope: "read write",
149
+ });
150
+
151
+ console.log(response.clientId, response.clientSecret);
152
+ ```
153
+
154
+ `registerClient` discovers the AS's `registration_endpoint` from
155
+ `.well-known/oauth-authorization-server`, posts the request as JSON, and
156
+ returns the issued client credentials. Throws `OAuthError` on RFC 6749 §5.2
157
+ error responses, a plain `Error` on missing `registration_endpoint` or
158
+ non-OAuth HTTP failures.
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
+
139
194
  ## API Overview
140
195
 
141
196
  ### JWKS Key Management
@@ -162,6 +217,18 @@ when the verifier is constructed with `enableMultiZone: true`.
162
217
  | `TokenExchangeClient` | `@keycardai/oauth/tokenExchange` | RFC 8693 token exchange client with auto-discovery, plus `impersonate()` for substitute-user exchange |
163
218
  | `TokenType` | `@keycardai/oauth/tokenExchange` | URN constants: `ACCESS_TOKEN`, `SUBSTITUTE_USER` |
164
219
  | `buildSubstituteUserToken` | `@keycardai/oauth/jwt/substituteUser` | Builds the unsigned subject JWT for impersonation calls |
220
+ | `registerClient` | `@keycardai/oauth/registration` | RFC 7591 dynamic client registration with auto-discovery |
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 }` |
165
232
 
166
233
  ### Server-tier Primitives
167
234
 
@@ -11,6 +11,8 @@ export { buildSubstituteUserToken } from "./jwt/substituteUser.js";
11
11
  export { TokenExchangeClient, TokenType } from "./tokenExchange.js";
12
12
  export type { TokenExchangeRequest, TokenResponse, TokenExchangeClientOptions, ExchangeOptions, ImpersonateRequest, } from "./tokenExchange.js";
13
13
  export type { ApplicationCredential } from "./credentials.js";
14
+ export { registerClient } from "./registration.js";
15
+ export type { ClientRegistrationRequest, ClientRegistrationResponse, RegisterClientOptions, } from "./registration.js";
14
16
  export { AccessContext, TokenVerifier, ClientSecret } from "./server/index.js";
15
17
  export type { ErrorDetail, AccessContextStatus, AccessToken, TokenVerifierOptions, ClientSecretCredentials, } from "./server/index.js";
16
18
  //# 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,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"}
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.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.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");
@@ -28,6 +28,8 @@ Object.defineProperty(exports, "buildSubstituteUserToken", { enumerable: true, g
28
28
  var tokenExchange_js_1 = require("./tokenExchange.js");
29
29
  Object.defineProperty(exports, "TokenExchangeClient", { enumerable: true, get: function () { return tokenExchange_js_1.TokenExchangeClient; } });
30
30
  Object.defineProperty(exports, "TokenType", { enumerable: true, get: function () { return tokenExchange_js_1.TokenType; } });
31
+ var registration_js_1 = require("./registration.js");
32
+ Object.defineProperty(exports, "registerClient", { enumerable: true, get: function () { return registration_js_1.registerClient; } });
31
33
  var index_js_1 = require("./server/index.js");
32
34
  Object.defineProperty(exports, "AccessContext", { enumerable: true, get: function () { return index_js_1.AccessContext; } });
33
35
  Object.defineProperty(exports, "TokenVerifier", { enumerable: true, get: function () { return index_js_1.TokenVerifier; } });
@@ -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,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"}
@@ -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,75 @@
1
+ /**
2
+ * RFC 7591 Dynamic Client Registration request metadata.
3
+ * Reference: https://datatracker.ietf.org/doc/html/rfc7591#section-2
4
+ */
5
+ export interface ClientRegistrationRequest {
6
+ clientName?: string;
7
+ clientUri?: string;
8
+ logoUri?: string;
9
+ tosUri?: string;
10
+ policyUri?: string;
11
+ softwareId?: string;
12
+ softwareVersion?: string;
13
+ jwksUri?: string;
14
+ jwks?: Record<string, unknown>;
15
+ tokenEndpointAuthMethod?: string;
16
+ redirectUris?: readonly string[];
17
+ grantTypes?: readonly string[];
18
+ responseTypes?: readonly string[];
19
+ scope?: string;
20
+ /**
21
+ * Vendor-extension or AS-specific fields not covered by the typed shape.
22
+ * Merged into the request body verbatim (snake_case keys preserved).
23
+ */
24
+ additionalMetadata?: Record<string, unknown>;
25
+ }
26
+ /**
27
+ * RFC 7591 Dynamic Client Registration response.
28
+ * Reference: https://datatracker.ietf.org/doc/html/rfc7591#section-3.2.1
29
+ */
30
+ export interface ClientRegistrationResponse {
31
+ clientId: string;
32
+ clientSecret?: string;
33
+ clientIdIssuedAt?: number;
34
+ clientSecretExpiresAt?: number;
35
+ clientName?: string;
36
+ clientUri?: string;
37
+ logoUri?: string;
38
+ tosUri?: string;
39
+ policyUri?: string;
40
+ softwareId?: string;
41
+ softwareVersion?: string;
42
+ jwksUri?: string;
43
+ jwks?: Record<string, unknown>;
44
+ tokenEndpointAuthMethod?: string;
45
+ redirectUris?: string[];
46
+ grantTypes?: string[];
47
+ responseTypes?: string[];
48
+ scope?: string[];
49
+ registrationAccessToken?: string;
50
+ registrationClientUri?: string;
51
+ /**
52
+ * The full unparsed response body. Useful for AS-specific extensions
53
+ * not captured by the typed fields above.
54
+ */
55
+ raw: Record<string, unknown>;
56
+ }
57
+ export interface RegisterClientOptions {
58
+ signal?: AbortSignal;
59
+ /** Request timeout in milliseconds. Ignored if `signal` is already provided. */
60
+ timeoutMs?: number;
61
+ }
62
+ /**
63
+ * Register a new OAuth 2.0 client with an authorization server (RFC 7591).
64
+ *
65
+ * Discovers `registration_endpoint` from the AS's
66
+ * `.well-known/oauth-authorization-server` metadata, POSTs the registration
67
+ * request as JSON, and returns the issued client credentials.
68
+ *
69
+ * Throws:
70
+ * - `Error` when the AS does not advertise `registration_endpoint`.
71
+ * - `OAuthError` when the AS returns an RFC 6749 §5.2 error response.
72
+ * - `Error` on non-OAuth HTTP failures or malformed responses.
73
+ */
74
+ export declare function registerClient(issuerUrl: string, request: ClientRegistrationRequest, options?: RegisterClientOptions): Promise<ClientRegistrationResponse>;
75
+ //# sourceMappingURL=registration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registration.d.ts","sourceRoot":"","sources":["../../src/registration.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9C;AAED;;;GAGG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,gFAAgF;IAChF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,yBAAyB,EAClC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,0BAA0B,CAAC,CAyDrC"}