@cloudflare/workers-auth 0.1.0 → 0.2.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.
@@ -2,5 +2,3 @@ var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
 
4
4
  export { __name };
5
- //# sourceMappingURL=chunk-PAWJFY3S.mjs.map
6
- //# sourceMappingURL=chunk-PAWJFY3S.mjs.map
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { UserError, ComplianceConfig } from '@cloudflare/workers-utils';
1
+ import { ApiCredentials, UserError, ComplianceConfig } from '@cloudflare/workers-utils';
2
2
 
3
3
  /**
4
4
  * The data that may be read from the on-disk user auth config file.
@@ -12,28 +12,29 @@ interface UserAuthConfig {
12
12
  api_token?: string;
13
13
  }
14
14
  /**
15
- * Returns the absolute path to the auth config TOML file.
15
+ * Pluggable persistence for the user auth config.
16
16
  *
17
- * The file lives under the global Wrangler config directory and is named
18
- * `default.toml` in production, or `<environment>.toml` for the staging /
19
- * other Cloudflare API environments.
20
- */
21
- declare function getAuthConfigFilePath(): string;
22
- /**
23
- * Writes the user auth config to disk.
24
- *
25
- * No in-memory cache to invalidate — auth state is read on demand by every call
26
- * site that needs it. Callers are responsible for any consumer-side cache
27
- * purging (e.g. via the {@link OAuthFlowContext.purgeOnLoginOrLogout} hook).
28
- */
29
- declare function writeAuthConfigFile(config: UserAuthConfig): void;
30
- /**
31
- * Reads the user auth config from disk.
32
- *
33
- * @throws if the file does not exist or cannot be parsed as TOML. Callers
34
- * typically catch this and treat the failure as "not logged in via local OAuth".
35
- */
36
- declare function readAuthConfigFile(): UserAuthConfig;
17
+ * This package does not ship a default implementation the consumer injects
18
+ * one via {@link OAuthFlowContext.storage} (and into {@link getAPIToken} /
19
+ * {@link readStoredAuthState}). Wrangler's default reads/writes a TOML file
20
+ * under the global Wrangler config directory; other CLIs can use a different
21
+ * location and/or serialization format (e.g. a JSONC file under a different
22
+ * CLI's XDG config directory).
23
+ */
24
+ interface AuthConfigStorage {
25
+ /**
26
+ * Read and parse the stored auth config.
27
+ * @throws if the backing store is missing or cannot be parsed. Callers treat
28
+ * a throw as "not logged in via local OAuth".
29
+ */
30
+ read(): UserAuthConfig;
31
+ /** Serialize and persist the auth config. */
32
+ write(config: UserAuthConfig): void;
33
+ /** Remove the backing store (used on logout). */
34
+ clear(): void;
35
+ /** Human-readable location of the backing store, for display and warnings. */
36
+ path(): string;
37
+ }
37
38
 
38
39
  interface GenerateAuthUrlProps {
39
40
  authUrl: string;
@@ -41,8 +42,8 @@ interface GenerateAuthUrlProps {
41
42
  scopes: string[];
42
43
  stateQueryParam: string;
43
44
  codeChallenge: string;
45
+ redirectUri: string;
44
46
  }
45
- declare const OAUTH_CALLBACK_URL = "http://localhost:8976/oauth/callback";
46
47
  /**
47
48
  * Build the OAuth 2.0 authorize URL for the Cloudflare auth endpoint.
48
49
  *
@@ -50,7 +51,7 @@ declare const OAUTH_CALLBACK_URL = "http://localhost:8976/oauth/callback";
50
51
  * substitute a deterministic implementation when a stable URL is needed
51
52
  * (e.g. for snapshot testing).
52
53
  */
53
- declare const generateAuthUrl: ({ authUrl, clientId, scopes, stateQueryParam, codeChallenge, }: GenerateAuthUrlProps) => string;
54
+ declare const generateAuthUrl: ({ authUrl, clientId, scopes, stateQueryParam, codeChallenge, redirectUri, }: GenerateAuthUrlProps) => string;
54
55
 
55
56
  /**
56
57
  * Generates random state to be passed for anti-csrf.
@@ -61,6 +62,22 @@ declare const generateAuthUrl: ({ authUrl, clientId, scopes, stateQueryParam, co
61
62
  */
62
63
  declare function generateRandomState(lengthOfState: number): string;
63
64
 
65
+ /**
66
+ * The branded OAuth consent pages the provider redirects the browser to after
67
+ * the user grants or denies consent.
68
+ */
69
+ interface OAuthConsentPages {
70
+ /** Redirect target shown after the user grants consent. */
71
+ granted: {
72
+ url: string;
73
+ };
74
+ /** Redirect target shown after the user denies consent, plus the error
75
+ * surfaced to the terminal. */
76
+ denied: {
77
+ url: string;
78
+ error: string;
79
+ };
80
+ }
64
81
  /**
65
82
  * Subset of the wrangler `logger` singleton used by the OAuth flow.
66
83
  * Consumers pass in an implementation that maps to their own logging surface.
@@ -107,6 +124,26 @@ interface OAuthFlowContext {
107
124
  * cache).
108
125
  */
109
126
  purgeOnLoginOrLogout?: () => void;
127
+ /**
128
+ * The OAuth client ID identifying the consuming CLI to the Cloudflare OAuth
129
+ * server. Consumer-specific (each CLI registers its own OAuth app), so it is
130
+ * required. Pass a function to resolve it lazily — e.g. so an env-var read at
131
+ * call time can switch between production and staging apps.
132
+ */
133
+ clientId: string | (() => string);
134
+ /**
135
+ * The branded consent pages the provider redirects to after the user grants
136
+ * or denies consent.
137
+ */
138
+ consent: OAuthConsentPages;
139
+ /**
140
+ * The `redirect_uri` registered on the consumer's OAuth app
141
+ */
142
+ redirectUri: string;
143
+ /**
144
+ * Persistence backend for the stored auth config.
145
+ */
146
+ storage: AuthConfigStorage;
110
147
  /**
111
148
  * Override the OAuth authorize URL generator. Used by tests to produce a
112
149
  * deterministic URL for snapshot testing. Defaults to the standard
@@ -121,6 +158,60 @@ interface OAuthFlowContext {
121
158
  generateRandomState?: typeof generateRandomState;
122
159
  }
123
160
 
161
+ /** `CLOUDFLARE_API_TOKEN` (legacy alias `CF_API_TOKEN`): a scoped API token. */
162
+ declare const getCloudflareAPITokenFromEnv: () => string | undefined;
163
+ /** `CLOUDFLARE_API_KEY` (legacy alias `CF_API_KEY`): the global API key. */
164
+ declare const getCloudflareGlobalAuthKeyFromEnv: () => string | undefined;
165
+ /** `CLOUDFLARE_EMAIL` (legacy alias `CF_EMAIL`): the account email, paired with
166
+ * the global API key. */
167
+ declare const getCloudflareGlobalAuthEmailFromEnv: () => string | undefined;
168
+ interface GetAuthFromEnvOptions {
169
+ /**
170
+ * Whether to honour the global API key + email pair
171
+ * (`CLOUDFLARE_API_KEY` + `CLOUDFLARE_EMAIL`, surfaced as
172
+ * `X-Auth-Key`/`X-Auth-Email`). Defaults to `true` (Wrangler's behaviour).
173
+ * CLIs that only support scoped API tokens / OAuth should pass `false`.
174
+ */
175
+ allowGlobalAuthKey?: boolean;
176
+ }
177
+ /**
178
+ * Resolve Cloudflare API credentials from environment variables.
179
+ *
180
+ * Priority (highest to lowest), matching Wrangler's historical order:
181
+ * 1. Global API key + email (`CLOUDFLARE_API_KEY` + `CLOUDFLARE_EMAIL`) —
182
+ * only when `allowGlobalAuthKey` is `true`.
183
+ * 2. API token (`CLOUDFLARE_API_TOKEN`).
184
+ *
185
+ * @returns the resolved credentials, or `undefined` when no env credentials
186
+ * are present.
187
+ */
188
+ declare function getAuthFromEnv(options?: GetAuthFromEnvOptions): ApiCredentials | undefined;
189
+ interface GetAPITokenOptions extends GetAuthFromEnvOptions {
190
+ /** Persistence backend for the stored OAuth token. */
191
+ storage: AuthConfigStorage;
192
+ /** Logger used to surface the one-time deprecated-v1-`api_token` warning. */
193
+ warningLogger?: Pick<OAuthFlowLogger, "warn">;
194
+ }
195
+ /**
196
+ * Resolve Cloudflare API credentials from the environment, falling back to the
197
+ * locally-stored OAuth token.
198
+ *
199
+ * Resolution order (highest to lowest):
200
+ * 1. {@link getAuthFromEnv} (env credentials).
201
+ * 2. The deprecated v1 `api_token` on disk (with a one-time warning).
202
+ * 3. The stored OAuth access token (from a previous interactive login).
203
+ *
204
+ * Note: this does NOT refresh an expired OAuth token. Callers that need a
205
+ * guaranteed-valid OAuth token should use the flow's
206
+ * `getOAuthTokenFromLocalState()` instead.
207
+ */
208
+ declare function getAPIToken(options: GetAPITokenOptions): ApiCredentials | undefined;
209
+ /**
210
+ * Like {@link getAPIToken}, but throws a {@link UserError} when no credentials
211
+ * are available.
212
+ */
213
+ declare function requireApiToken(options: GetAPITokenOptions): ApiCredentials;
214
+
124
215
  /**
125
216
  * Clear internal caches. Exported for use in tests only.
126
217
  */
@@ -165,15 +256,6 @@ declare function getCloudflareAccessHeaders(options: {
165
256
  isNonInteractiveOrCI: () => boolean;
166
257
  }): Promise<Record<string, string>>;
167
258
 
168
- /**
169
- * `WRANGLER_CLIENT_ID` is a UUID that is used to identify Wrangler
170
- * to the Cloudflare APIs.
171
- *
172
- * Normally you should not need to set this explicitly.
173
- * If you want to switch to the staging environment set the
174
- * `WRANGLER_API_ENVIRONMENT=staging` environment variable instead.
175
- */
176
- declare const getClientIdFromEnv: () => string;
177
259
  /**
178
260
  * `WRANGLER_AUTH_DOMAIN` is the URL base domain that is used
179
261
  * to access OAuth URLs for the Cloudflare APIs.
@@ -236,11 +318,21 @@ declare const getCfAuthorizationTokenFromEnv: () => string | undefined;
236
318
 
237
319
  /**
238
320
  * A list of OAuth2AuthCodePKCE errors.
321
+ *
322
+ * Instances may carry the structured details from the OAuth provider's
323
+ * `error`, `error_description` and `error_uri` query parameters (RFC 6749
324
+ * §4.1.2.1) so callers can render them — see {@link toErrorClass}.
239
325
  */
240
326
  declare class ErrorOAuth2 extends UserError {
327
+ /** The OAuth `error` code returned by the provider (e.g. `invalid_scope`). */
328
+ code?: string;
329
+ /** The OAuth `error_description` returned by the provider, if any. */
330
+ description?: string;
331
+ /** The OAuth `error_uri` returned by the provider, if any. */
332
+ uri?: string;
241
333
  toString(): string;
242
334
  }
243
- declare class ErrorUnknown extends UserError {
335
+ declare class ErrorUnknown extends ErrorOAuth2 {
244
336
  toString(): string;
245
337
  }
246
338
  declare class ErrorNoAuthCode extends ErrorOAuth2 {
@@ -299,10 +391,41 @@ declare class ErrorUnsupportedGrantType extends ErrorAccessTokenResponse {
299
391
  toString(): string;
300
392
  }
301
393
  /**
302
- * Translate the raw error strings returned from the server into error classes.
394
+ * Translate an OAuth error response from the provider into one of our error
395
+ * classes. The `error_description` and `error_uri` parameters (RFC 6749
396
+ * §4.1.2.1) are included in the message when present so the user sees the
397
+ * specific reason for the failure rather than just the bare error code, and
398
+ * are also attached as structured fields so the HTTP callback handler can
399
+ * render them on the browser-facing error page.
303
400
  */
304
- declare function toErrorClass(rawError: string): ErrorOAuth2 | ErrorUnknown;
401
+ declare function toErrorClass(rawError: string, description?: string, uri?: string): ErrorOAuth2 | ErrorUnknown;
305
402
 
403
+ /**
404
+ * Reason why {@link OAuthFlowAPI.loginOrRefreshIfRequired} could not
405
+ * authenticate the user.
406
+ */
407
+ type LoginOrRefreshFailureReason =
408
+ /** no stored credentials and the environment is non-interactive (CI, piped stdin, etc.) so a browser login cannot be started. */
409
+ "no-credentials-non-interactive"
410
+ /** stored credentials and the interactive login attempt was unsuccessful (user cancelled, etc.). */
411
+ | "no-credentials-login-failed"
412
+ /** the stored token has expired, refresh failed, and the environment is non-interactive so a browser login cannot be started. */
413
+ | "token-expired-non-interactive"
414
+ /** the stored token has expired, refresh failed, and the interactive login attempt was unsuccessful. */
415
+ | "token-expired-login-failed";
416
+ /**
417
+ * Discriminated union returned by {@link OAuthFlowAPI.loginOrRefreshIfRequired}.
418
+ *
419
+ * When `loggedIn` is `true` the caller can proceed. When `false`, `reason`
420
+ * describes why authentication failed so the caller can surface a
421
+ * targeted error message.
422
+ */
423
+ type LoginOrRefreshResult = {
424
+ loggedIn: true;
425
+ } | {
426
+ loggedIn: false;
427
+ reason: LoginOrRefreshFailureReason;
428
+ };
306
429
  /**
307
430
  * Options for an interactive OAuth login.
308
431
  */
@@ -354,11 +477,12 @@ interface OAuthFlowAPI {
354
477
  * Scopes are required in case an interactive login is triggered — the
355
478
  * consumer's scope catalog lives outside this package.
356
479
  *
357
- * @returns `true` when the user is logged in (or env credentials are
358
- * present), `false` when interactive login was needed but skipped (e.g.
359
- * non-interactive environment).
480
+ * @returns `{ loggedIn: true }` when the user is authenticated (or env
481
+ * credentials are present). When authentication fails, returns
482
+ * `{ loggedIn: false, reason }` describing why — see
483
+ * {@link LoginOrRefreshFailureReason}.
360
484
  */
361
- loginOrRefreshIfRequired(props: LoginProps): Promise<boolean>;
485
+ loginOrRefreshIfRequired(props: LoginProps): Promise<LoginOrRefreshResult>;
362
486
  /**
363
487
  * Read the OAuth access token from local state, refreshing it first if
364
488
  * needed. Returns `undefined` when there is no stored OAuth token or the
@@ -466,10 +590,14 @@ interface StoredAuthState {
466
590
  * @param options.warningLogger if provided, a one-time warning is emitted when a
467
591
  * deprecated v1 `api_token` is found on disk. Pass the consumer's logger (e.g.
468
592
  * wrangler's logger singleton) to surface this to the user.
593
+ * @param options.storage the persistence backend to read from, injected by the
594
+ * consumer (e.g. wrangler's TOML-file-on-disk storage under the global Wrangler
595
+ * config directory).
469
596
  */
470
- declare function readStoredAuthState(options?: {
597
+ declare function readStoredAuthState(options: {
471
598
  configOverride?: UserAuthConfig;
472
599
  warningLogger?: Pick<OAuthFlowLogger, "warn">;
600
+ storage: AuthConfigStorage;
473
601
  }): StoredAuthState;
474
602
 
475
- export { type AccessToken, ErrorAccessDenied, ErrorAccessTokenResponse, ErrorAuthenticationGrant, ErrorInvalidClient, ErrorInvalidGrant, ErrorInvalidJson, ErrorInvalidRequest, ErrorInvalidReturnedStateParam, ErrorInvalidScope, ErrorInvalidToken, ErrorNoAuthCode, ErrorOAuth2, ErrorServerError, ErrorTemporarilyUnavailable, ErrorUnauthorizedClient, ErrorUnknown, ErrorUnsupportedGrantType, ErrorUnsupportedResponseType, type LoginProps, OAUTH_CALLBACK_URL, type OAuthFlowAPI, type OAuthFlowContext, type OAuthFlowLogger, type OAuthFlowState, type PKCECodes, PKCE_CHARSET, RECOMMENDED_CODE_VERIFIER_LENGTH, RECOMMENDED_STATE_LENGTH, type RefreshToken, type StoredAuthState, type UserAuthConfig, base64urlEncode, clearAccessCaches, createOAuthFlow, domainUsesAccess, generateAuthUrl, generatePKCECodes, generateRandomState, getAccessClientIdFromEnv, getAccessClientSecretFromEnv, getAccessHeaders, getAuthConfigFilePath, getAuthDomainFromEnv, getAuthUrlFromEnv, getCfAuthorizationTokenFromEnv, getClientIdFromEnv, getCloudflareAccessHeaders, getRevokeUrlFromEnv, getTokenUrlFromEnv, readAuthConfigFile, readStoredAuthState, toErrorClass, writeAuthConfigFile };
603
+ export { type AccessToken, type AuthConfigStorage, ErrorAccessDenied, ErrorAccessTokenResponse, ErrorAuthenticationGrant, ErrorInvalidClient, ErrorInvalidGrant, ErrorInvalidJson, ErrorInvalidRequest, ErrorInvalidReturnedStateParam, ErrorInvalidScope, ErrorInvalidToken, ErrorNoAuthCode, ErrorOAuth2, ErrorServerError, ErrorTemporarilyUnavailable, ErrorUnauthorizedClient, ErrorUnknown, ErrorUnsupportedGrantType, ErrorUnsupportedResponseType, type GetAPITokenOptions, type GetAuthFromEnvOptions, type LoginOrRefreshFailureReason, type LoginOrRefreshResult, type LoginProps, type OAuthConsentPages, type OAuthFlowAPI, type OAuthFlowContext, type OAuthFlowLogger, type OAuthFlowState, type PKCECodes, PKCE_CHARSET, RECOMMENDED_CODE_VERIFIER_LENGTH, RECOMMENDED_STATE_LENGTH, type RefreshToken, type StoredAuthState, type UserAuthConfig, base64urlEncode, clearAccessCaches, createOAuthFlow, domainUsesAccess, generateAuthUrl, generatePKCECodes, generateRandomState, getAPIToken, getAccessClientIdFromEnv, getAccessClientSecretFromEnv, getAccessHeaders, getAuthDomainFromEnv, getAuthFromEnv, getAuthUrlFromEnv, getCfAuthorizationTokenFromEnv, getCloudflareAPITokenFromEnv, getCloudflareAccessHeaders, getCloudflareGlobalAuthEmailFromEnv, getCloudflareGlobalAuthKeyFromEnv, getRevokeUrlFromEnv, getTokenUrlFromEnv, readStoredAuthState, requireApiToken, toErrorClass };