@cloudflare/workers-auth 0.1.1 → 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.
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.
@@ -318,6 +400,32 @@ declare class ErrorUnsupportedGrantType extends ErrorAccessTokenResponse {
318
400
  */
319
401
  declare function toErrorClass(rawError: string, description?: string, uri?: string): ErrorOAuth2 | ErrorUnknown;
320
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
+ };
321
429
  /**
322
430
  * Options for an interactive OAuth login.
323
431
  */
@@ -369,11 +477,12 @@ interface OAuthFlowAPI {
369
477
  * Scopes are required in case an interactive login is triggered — the
370
478
  * consumer's scope catalog lives outside this package.
371
479
  *
372
- * @returns `true` when the user is logged in (or env credentials are
373
- * present), `false` when interactive login was needed but skipped (e.g.
374
- * 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}.
375
484
  */
376
- loginOrRefreshIfRequired(props: LoginProps): Promise<boolean>;
485
+ loginOrRefreshIfRequired(props: LoginProps): Promise<LoginOrRefreshResult>;
377
486
  /**
378
487
  * Read the OAuth access token from local state, refreshing it first if
379
488
  * needed. Returns `undefined` when there is no stored OAuth token or the
@@ -481,10 +590,14 @@ interface StoredAuthState {
481
590
  * @param options.warningLogger if provided, a one-time warning is emitted when a
482
591
  * deprecated v1 `api_token` is found on disk. Pass the consumer's logger (e.g.
483
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).
484
596
  */
485
- declare function readStoredAuthState(options?: {
597
+ declare function readStoredAuthState(options: {
486
598
  configOverride?: UserAuthConfig;
487
599
  warningLogger?: Pick<OAuthFlowLogger, "warn">;
600
+ storage: AuthConfigStorage;
488
601
  }): StoredAuthState;
489
602
 
490
- 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 };