diff --git a/.changeset/large-pillows-clap.md b/.changeset/large-pillows-clap.md new file mode 100644 index 000000000000..56e9a5952842 --- /dev/null +++ b/.changeset/large-pillows-clap.md @@ -0,0 +1,11 @@ +--- +"wrangler": patch +--- + +fix: improve authentication logging and warnings + +- If a user has previously logged in via Wrangler 1 with an API token, we now display a helpful warning. +- When logging in and out, we no longer display the path to the internal user auh config file. +- When logging in, we now display an initial message to indicate the authentication flow is starting. + +Fixes [#526](https://github.com/cloudflare/wrangler2/issues/526) diff --git a/packages/wrangler/src/__tests__/logout.test.ts b/packages/wrangler/src/__tests__/logout.test.ts index a65f00d6b719..2824934c198f 100644 --- a/packages/wrangler/src/__tests__/logout.test.ts +++ b/packages/wrangler/src/__tests__/logout.test.ts @@ -38,10 +38,7 @@ describe("wrangler", () => { reinitialiseAuthTokens(); await runWrangler("logout"); - expect(std.out).toMatchInlineSnapshot(` - "💁 Wrangler is configured with an OAuth token. The token has been successfully revoked - Removing ./home/.wrangler/config/default.toml.. success!" - `); + expect(std.out).toMatchInlineSnapshot(`"Successfully logged out."`); // Make sure that we made the request to logout. expect(fetchMock).toHaveBeenCalledTimes(1); diff --git a/packages/wrangler/src/__tests__/whoami.test.tsx b/packages/wrangler/src/__tests__/whoami.test.tsx index b54ec5e558e7..d273a8b68b7b 100644 --- a/packages/wrangler/src/__tests__/whoami.test.tsx +++ b/packages/wrangler/src/__tests__/whoami.test.tsx @@ -3,11 +3,13 @@ import React from "react"; import { reinitialiseAuthTokens, writeAuthConfigFile } from "../user"; import { getUserInfo, WhoAmI } from "../whoami"; import { setMockResponse } from "./helpers/mock-cfetch"; +import { mockConsoleMethods } from "./helpers/mock-console"; import { runInTempDir } from "./helpers/run-in-tmp"; import type { UserInfo } from "../whoami"; describe("getUserInfo()", () => { runInTempDir({ homedir: "./home" }); + const std = mockConsoleMethods(); it("should return undefined if there is no config file", async () => { const userInfo = await getUserInfo(); @@ -51,6 +53,17 @@ describe("getUserInfo()", () => { ], }); }); + + it("should display a warning message if the config file contains a legacy api_token field", async () => { + writeAuthConfigFile({ api_token: "API_TOKEN" }); + await reinitialiseAuthTokens(); + await getUserInfo(); + expect(std.warn).toMatchInlineSnapshot(` + "It looks like you have used Wrangler 1's \`config\` command to login with an API token. + This is no longer supported in the current version of Wrangler. + If you wish to authenticate via an API token then please set the \`CLOUDFLARE_API_TOKEN\` environment variable." + `); + }); }); describe("WhoAmI component", () => { diff --git a/packages/wrangler/src/cfetch/internal.ts b/packages/wrangler/src/cfetch/internal.ts index ff1eabaf2fda..72e725420837 100644 --- a/packages/wrangler/src/cfetch/internal.ts +++ b/packages/wrangler/src/cfetch/internal.ts @@ -89,11 +89,11 @@ async function requireLoggedIn(): Promise { } function requireApiToken(): string { - const apiToken = getAPIToken(); - if (!apiToken) { + const authToken = getAPIToken(); + if (!authToken) { throw new Error("No API token found."); } - return apiToken; + return authToken; } function addAuthorizationHeader( diff --git a/packages/wrangler/src/user.tsx b/packages/wrangler/src/user.tsx index 8ee474ce2dd5..551a1e434f79 100644 --- a/packages/wrangler/src/user.tsx +++ b/packages/wrangler/src/user.tsx @@ -270,6 +270,8 @@ interface State extends AuthTokens { interface AuthTokens { accessToken?: AccessToken; refreshToken?: RefreshToken; + /** @deprecated - this field was only provided by the deprecated `wrangler1 config` command. */ + apiToken?: string; } /** @@ -285,7 +287,8 @@ export interface UserAuthConfig { oauth_token?: string; refresh_token?: string; expiration_time?: string; - // api_token?: string; + /** @deprecated - this field was only provided by the deprecated `wrangler1 config` command. */ + api_token?: string; } interface RefreshToken { @@ -357,7 +360,7 @@ function getAuthTokens(): AuthTokens { } // otherwise try loading from the user auth config file. - const { oauth_token, refresh_token, expiration_time } = + const { oauth_token, refresh_token, expiration_time, api_token } = readAuthConfigFile(); if (oauth_token) { @@ -369,6 +372,8 @@ function getAuthTokens(): AuthTokens { }, refreshToken: { value: refresh_token ?? "" }, }; + } else if (api_token) { + return { apiToken: api_token }; } else { return {}; } @@ -385,6 +390,13 @@ export function reinitialiseAuthTokens(): void { } export function getAPIToken(): string | undefined { + if (LocalState.apiToken) { + console.warn( + "It looks like you have used Wrangler 1's `config` command to login with an API token.\n" + + "This is no longer supported in the current version of Wrangler.\n" + + "If you wish to authenticate via an API token then please set the `CLOUDFLARE_API_TOKEN` environment variable." + ); + } return LocalState.accessToken?.value; } @@ -847,7 +859,7 @@ export async function loginOrRefreshIfRequired( ): Promise { // TODO: if there already is a token, then try refreshing // TODO: ask permission before opening browser - if (LocalState.accessToken === undefined) { + if (!getAPIToken()) { // Not logged in. // If we are not interactive, we cannot ask the user to login return isInteractive && (await login()); @@ -859,6 +871,7 @@ export async function loginOrRefreshIfRequired( } export async function login(props?: LoginProps): Promise { + console.log("Attempting to login via OAuth..."); const urlToOpen = await getAuthURL(props?.scopes); await openInBrowser(urlToOpen); let server: http.Server; @@ -930,9 +943,7 @@ export async function login(props?: LoginProps): Promise { res.end(() => { finish(true); }); - console.log( - `Successfully configured. You can find your configuration file at: ${os.homedir()}/${USER_AUTH_CONFIG_FILE}` - ); + console.log(`Successfully logged in.`); return; } @@ -1009,12 +1020,8 @@ export async function logout(): Promise { }, }); await response.text(); // blank text? would be nice if it was something meaningful - console.log( - "💁 Wrangler is configured with an OAuth token. The token has been successfully revoked" - ); - // delete the file rmSync(path.join(os.homedir(), USER_AUTH_CONFIG_FILE)); - console.log(`Removing ${os.homedir()}/${USER_AUTH_CONFIG_FILE}.. success!`); + console.log(`Successfully logged out.`); } export function listScopes(message = "💁 Available scopes:"): void {