From a52b36d15798fbfb154865345cb12a0670a728b3 Mon Sep 17 00:00:00 2001 From: Gonzalo Riestra Date: Fri, 20 Mar 2026 11:27:19 +0100 Subject: [PATCH 1/2] Add SHOPIFY_CLI_TOKEN and add a deprecation warning for SHOPIFY_CLI_PARTNERS_TOKEN --- .changeset/heavy-adults-walk.md | 6 +++ .../app-management-client.ts | 4 +- .../cli-kit/src/private/node/constants.ts | 1 + .../cli-kit/src/private/node/session.test.ts | 10 ++-- packages/cli-kit/src/private/node/session.ts | 8 +-- .../src/private/node/session/exchange.ts | 16 +++--- .../src/public/node/environment.test.ts | 54 +++++++++++++++++++ .../cli-kit/src/public/node/environment.ts | 30 +++++++---- .../cli-kit/src/public/node/hooks/prerun.ts | 2 + .../cli-kit/src/public/node/session.test.ts | 6 +-- packages/cli-kit/src/public/node/session.ts | 6 +-- 11 files changed, 109 insertions(+), 34 deletions(-) create mode 100644 .changeset/heavy-adults-walk.md create mode 100644 packages/cli-kit/src/public/node/environment.test.ts diff --git a/.changeset/heavy-adults-walk.md b/.changeset/heavy-adults-walk.md new file mode 100644 index 00000000000..cb20d31c124 --- /dev/null +++ b/.changeset/heavy-adults-walk.md @@ -0,0 +1,6 @@ +--- +'@shopify/cli-kit': minor +'@shopify/app': minor +--- + +Add support for SHOPIFY_CLI_TOKEN env var and add a deprecation warning for SHOPIFY_CLI_PARTNERS_TOKEN diff --git a/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts b/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts index 33cf9e57719..0a7493164a3 100644 --- a/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts +++ b/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts @@ -142,7 +142,7 @@ import { AppLogsSubscribeMutationVariables, } from '../../api/graphql/app-management/generated/app-logs-subscribe.js' import {SourceExtension} from '../../api/graphql/app-management/generated/types.js' -import {getPartnersToken} from '@shopify/cli-kit/node/environment' +import {getCliToken} from '@shopify/cli-kit/node/environment' import {ensureAuthenticatedAppManagementAndBusinessPlatform, Session} from '@shopify/cli-kit/node/session' import {isUnitTest} from '@shopify/cli-kit/node/context/local' import {AbortError, BugError} from '@shopify/cli-kit/node/error' @@ -294,7 +294,7 @@ export class AppManagementClient implements DeveloperPlatformClient { unauthorizedHandler: this.createUnauthorizedHandler('businessPlatform'), }) - if (getPartnersToken() && userInfoResult.currentUserAccount) { + if (getCliToken() && userInfoResult.currentUserAccount) { const organizations = userInfoResult.currentUserAccount.organizations.nodes.map((org) => ({ name: org.name, })) diff --git a/packages/cli-kit/src/private/node/constants.ts b/packages/cli-kit/src/private/node/constants.ts index 3672b8b4c29..4a6a94f0beb 100644 --- a/packages/cli-kit/src/private/node/constants.ts +++ b/packages/cli-kit/src/private/node/constants.ts @@ -21,6 +21,7 @@ export const environmentVariables = { env: 'SHOPIFY_CLI_ENV', firstPartyDev: 'SHOPIFY_CLI_1P_DEV', noAnalytics: 'SHOPIFY_CLI_NO_ANALYTICS', + cliToken: 'SHOPIFY_CLI_TOKEN', partnersToken: 'SHOPIFY_CLI_PARTNERS_TOKEN', runAsUser: 'SHOPIFY_RUN_AS_USER', serviceEnv: 'SHOPIFY_SERVICE_ENV', diff --git a/packages/cli-kit/src/private/node/session.test.ts b/packages/cli-kit/src/private/node/session.test.ts index 08eda6acff3..2c9d7a12a14 100644 --- a/packages/cli-kit/src/private/node/session.test.ts +++ b/packages/cli-kit/src/private/node/session.test.ts @@ -24,7 +24,7 @@ import * as fqdnModule from '../../public/node/context/fqdn.js' import {themeToken} from '../../public/node/context/local.js' import {partnersRequest} from '../../public/node/api/partners.js' import {businessPlatformRequest} from '../../public/node/api/business-platform.js' -import {getPartnersToken} from '../../public/node/environment.js' +import {getCliToken} from '../../public/node/environment.js' import {nonRandomUUID} from '../../public/node/crypto.js' import {terminalSupportsPrompting} from '../../public/node/system.js' @@ -319,7 +319,7 @@ describe('when existing session is valid', () => { // Given vi.mocked(validateSession).mockResolvedValueOnce('ok') vi.mocked(fetchSessions).mockResolvedValue(validSessions) - vi.mocked(getPartnersToken).mockReturnValue('custom_cli_token') + vi.mocked(getCliToken).mockReturnValue('custom_cli_token') const expected = {...validTokens, partners: 'custom_partners_token'} // When @@ -450,7 +450,7 @@ describe('getLastSeenUserIdAfterAuth', () => { test('returns UUID based on partners token if present in environment', async () => { // Given vi.mocked(getCurrentSessionId).mockReturnValue(undefined) - vi.mocked(getPartnersToken).mockReturnValue('partners-token-456') + vi.mocked(getCliToken).mockReturnValue('partners-token-456') // When const userId = await getLastSeenUserIdAfterAuth() @@ -540,7 +540,7 @@ describe('setLastSeenUserIdAfterAuth', () => { describe('getLastSeenAuthMethod', () => { beforeEach(() => { vi.mocked(getCurrentSessionId).mockReturnValue(undefined) - vi.mocked(getPartnersToken).mockReturnValue(undefined) + vi.mocked(getCliToken).mockReturnValue(undefined) vi.mocked(themeToken).mockReturnValue(undefined) setLastSeenAuthMethod('none') }) @@ -571,7 +571,7 @@ describe('getLastSeenAuthMethod', () => { test('returns partners_token if there is a partners token in the environment', async () => { // Given - vi.mocked(getPartnersToken).mockReturnValue('partners-token-456') + vi.mocked(getCliToken).mockReturnValue('partners-token-456') // When const method = await getLastSeenAuthMethod() diff --git a/packages/cli-kit/src/private/node/session.ts b/packages/cli-kit/src/private/node/session.ts index 6f87d00c66d..91cd578c5b7 100644 --- a/packages/cli-kit/src/private/node/session.ts +++ b/packages/cli-kit/src/private/node/session.ts @@ -19,7 +19,7 @@ import {outputContent, outputToken, outputDebug, outputCompleted} from '../../pu import {firstPartyDev, themeToken} from '../../public/node/context/local.js' import {AbortError} from '../../public/node/error.js' import {normalizeStoreFqdn, identityFqdn} from '../../public/node/context/fqdn.js' -import {getIdentityTokenInformation, getPartnersToken} from '../../public/node/environment.js' +import {getIdentityTokenInformation, getCliToken} from '../../public/node/environment.js' import {AdminSession, logout} from '../../public/node/session.js' import {nonRandomUUID} from '../../public/node/crypto.js' import {isEmpty} from '../../public/common/object.js' @@ -137,7 +137,7 @@ export async function getLastSeenUserIdAfterAuth(): Promise { const currentSessionId = getCurrentSessionId() if (currentSessionId) return currentSessionId - const customToken = getPartnersToken() ?? themeToken() + const customToken = getCliToken() ?? themeToken() return customToken ? nonRandomUUID(customToken) : 'unknown' } @@ -162,7 +162,7 @@ export async function getLastSeenAuthMethod(): Promise { if (getCurrentSessionId()) return 'device_auth' - const partnersToken = getPartnersToken() + const partnersToken = getCliToken() if (partnersToken) return 'partners_token' const themePassword = themeToken() @@ -264,7 +264,7 @@ ${outputToken.json(applications)} const tokens = await tokensFor(applications, completeSession) // Overwrite partners token if using a custom CLI Token - const envToken = getPartnersToken() + const envToken = getCliToken() if (envToken && applications.partnersApi) { tokens.partners = (await exchangeCustomPartnerToken(envToken)).accessToken } diff --git a/packages/cli-kit/src/private/node/session/exchange.ts b/packages/cli-kit/src/private/node/session/exchange.ts index ebf49f3d6a9..7b09d611af6 100644 --- a/packages/cli-kit/src/private/node/session/exchange.ts +++ b/packages/cli-kit/src/private/node/session/exchange.ts @@ -70,8 +70,8 @@ export async function refreshAccessToken(currentToken: IdentityToken): Promise { @@ -110,8 +110,8 @@ export async function exchangeCustomPartnerToken(token: string): Promise<{access } /** - * Given a custom CLI token passed as ENV variable, request a valid App Management API token - * @param token - The CLI token passed as ENV variable `SHOPIFY_CLI_PARTNERS_TOKEN` + * Given a custom CLI token passed as ENV variable, request a valid App Management API token. + * @param token - The CLI token passed as ENV variable `SHOPIFY_CLI_TOKEN` * @returns An instance with the application access tokens. */ export async function exchangeCliTokenForAppManagementAccessToken( @@ -121,8 +121,8 @@ export async function exchangeCliTokenForAppManagementAccessToken( } /** - * Given a custom CLI token passed as ENV variable, request a valid Business Platform API token - * @param token - The CLI token passed as ENV variable `SHOPIFY_CLI_PARTNERS_TOKEN` + * Given a custom CLI token passed as ENV variable, request a valid Business Platform API token. + * @param token - The CLI token passed as ENV variable `SHOPIFY_CLI_TOKEN` * @returns An instance with the application access tokens. */ export async function exchangeCliTokenForBusinessPlatformAccessToken( diff --git a/packages/cli-kit/src/public/node/environment.test.ts b/packages/cli-kit/src/public/node/environment.test.ts new file mode 100644 index 00000000000..2672fdb09c2 --- /dev/null +++ b/packages/cli-kit/src/public/node/environment.test.ts @@ -0,0 +1,54 @@ +import {getCliToken, showEnvVarDeprecationWarnings} from './environment.js' +import {mockAndCaptureOutput} from './testing/output.js' +import {environmentVariables} from '../../private/node/constants.js' +import {describe, expect, test, beforeEach} from 'vitest' + +const outputMock = mockAndCaptureOutput() + +beforeEach(() => { + outputMock.clear() + delete process.env[environmentVariables.cliToken] + delete process.env[environmentVariables.partnersToken] +}) + +describe('getCliToken', () => { + test('returns SHOPIFY_CLI_TOKEN when set', () => { + process.env[environmentVariables.cliToken] = 'new-token' + + expect(getCliToken()).toBe('new-token') + }) + + test('returns SHOPIFY_CLI_PARTNERS_TOKEN when SHOPIFY_CLI_TOKEN is not set', () => { + process.env[environmentVariables.partnersToken] = 'old-token' + + expect(getCliToken()).toBe('old-token') + }) + + test('prefers SHOPIFY_CLI_TOKEN over SHOPIFY_CLI_PARTNERS_TOKEN', () => { + process.env[environmentVariables.cliToken] = 'new-token' + process.env[environmentVariables.partnersToken] = 'old-token' + + expect(getCliToken()).toBe('new-token') + }) + + test('returns undefined when neither env var is set', () => { + expect(getCliToken()).toBeUndefined() + }) +}) + +describe('showEnvVarDeprecationWarnings', () => { + test('shows warning when SHOPIFY_CLI_PARTNERS_TOKEN is set', () => { + process.env[environmentVariables.partnersToken] = 'old-token' + + showEnvVarDeprecationWarnings() + + expect(outputMock.warn()).toMatch(/SHOPIFY_CLI_PARTNERS_TOKEN/) + expect(outputMock.warn()).toMatch(/SHOPIFY_CLI_TOKEN/) + }) + + test('does not show warning when SHOPIFY_CLI_PARTNERS_TOKEN is not set', () => { + showEnvVarDeprecationWarnings() + + expect(outputMock.warn()).toBe('') + }) +}) diff --git a/packages/cli-kit/src/public/node/environment.ts b/packages/cli-kit/src/public/node/environment.ts index 653b4895d75..6e12203ddf0 100644 --- a/packages/cli-kit/src/public/node/environment.ts +++ b/packages/cli-kit/src/public/node/environment.ts @@ -1,6 +1,7 @@ import {nonRandomUUID} from './crypto.js' import {isTruthy} from './context/utilities.js' import {sniffForJson} from './path.js' +import {renderWarning} from './ui.js' import {environmentVariables, systemEnvironmentVariables} from '../../private/node/constants.js' /** @@ -18,21 +19,32 @@ export function getEnvironmentVariables(): NodeJS.ProcessEnv { } /** - * Returns the value of the SHOPIFY_CLI_PARTNERS_TOKEN environment variable. + * Returns the value of the SHOPIFY_CLI_TOKEN environment variable, + * falling back to the deprecated SHOPIFY_CLI_PARTNERS_TOKEN. * - * @returns Current process environment variables. + * @returns The CLI token value, or undefined if neither env var is set. */ -export function getPartnersToken(): string | undefined { - return getEnvironmentVariables()[environmentVariables.partnersToken] +export function getCliToken(): string | undefined { + const env = getEnvironmentVariables() + return env[environmentVariables.cliToken] ?? env[environmentVariables.partnersToken] } /** - * Check if the current proccess is running using the partners token. - * - * @returns True if the current proccess is running using the partners token. + * Shows deprecation warnings for environment variables that have been renamed. + * Currently warns when SHOPIFY_CLI_PARTNERS_TOKEN is used instead of SHOPIFY_CLI_TOKEN. */ -export function usePartnersToken(): boolean { - return getPartnersToken() !== undefined +export function showEnvVarDeprecationWarnings(): void { + const env = getEnvironmentVariables() + if (env[environmentVariables.partnersToken]) { + renderWarning({ + headline: [ + 'The environment variable', + {command: environmentVariables.partnersToken}, + 'has been deprecated and will eventually be removed.', + ], + body: ['Please use', {command: environmentVariables.cliToken}, 'instead.'], + }) + } } /** diff --git a/packages/cli-kit/src/public/node/hooks/prerun.ts b/packages/cli-kit/src/public/node/hooks/prerun.ts index b64c6c21cda..9f3681bcbc7 100644 --- a/packages/cli-kit/src/public/node/hooks/prerun.ts +++ b/packages/cli-kit/src/public/node/hooks/prerun.ts @@ -1,6 +1,7 @@ import {CLI_KIT_VERSION} from '../../common/version.js' import {checkForNewVersion, checkForCachedNewVersion} from '../node-package-manager.js' import {startAnalytics} from '../../../private/node/analytics.js' +import {showEnvVarDeprecationWarnings} from '../environment.js' import {outputDebug, outputWarn} from '../output.js' import {getOutputUpdateCLIReminder} from '../upgrade.js' import Command from '../base-command.js' @@ -23,6 +24,7 @@ export const hook: Hook.Prerun = async (options) => { }) const args = options.argv await warnOnAvailableUpgrade() + showEnvVarDeprecationWarnings() outputDebug(`Running command ${commandContent.command}`) await startAnalytics({commandContent, args, commandClass: options.Command as unknown as typeof Command}) fetchNotificationsInBackground(options.Command.id) diff --git a/packages/cli-kit/src/public/node/session.test.ts b/packages/cli-kit/src/public/node/session.test.ts index c391dea79a4..a032326c810 100644 --- a/packages/cli-kit/src/public/node/session.test.ts +++ b/packages/cli-kit/src/public/node/session.test.ts @@ -8,7 +8,7 @@ import { ensureAuthenticatedThemes, } from './session.js' -import {getPartnersToken} from './environment.js' +import {getCliToken} from './environment.js' import {shopifyFetch} from './http.js' import {ApplicationToken} from '../../private/node/session/schema.js' import {ensureAuthenticated, setLastSeenAuthMethod, setLastSeenUserIdAfterAuth} from '../../private/node/session.js' @@ -136,7 +136,7 @@ describe('ensureAuthenticatedPartners', () => { accessToken: partnersToken.accessToken, userId: '575e2102-cb13-7bea-4631-ce3469eac491cdcba07d', }) - vi.mocked(getPartnersToken).mockReturnValue('custom_cli_token') + vi.mocked(getCliToken).mockReturnValue('custom_cli_token') // When const got = await ensureAuthenticatedPartners([]) @@ -253,7 +253,7 @@ describe('ensureAuthenticatedAppManagementAndBusinessPlatform', () => { test('returns app managment and business platform tokens if CLI token envvar is defined', async () => { // Given - vi.mocked(getPartnersToken).mockReturnValue('custom_cli_token') + vi.mocked(getCliToken).mockReturnValue('custom_cli_token') vi.mocked(exchangeCliTokenForAppManagementAccessToken).mockResolvedValueOnce({ accessToken: 'app-management-token', userId: '575e2102-cb13-7bea-4631-ce3469eac491cdcba07d', diff --git a/packages/cli-kit/src/public/node/session.ts b/packages/cli-kit/src/public/node/session.ts index c1ddcf2038f..9757e55862e 100644 --- a/packages/cli-kit/src/public/node/session.ts +++ b/packages/cli-kit/src/public/node/session.ts @@ -1,6 +1,6 @@ import {shopifyFetch} from './http.js' import {nonRandomUUID} from './crypto.js' -import {getPartnersToken} from './environment.js' +import {getCliToken} from './environment.js' import {AbortError, BugError} from './error.js' import {outputContent, outputToken, outputDebug} from './output.js' import * as sessionStore from '../../private/node/session/store.js' @@ -110,7 +110,7 @@ export async function ensureAuthenticatedPartners( outputDebug(outputContent`Ensuring that the user is authenticated with the Partners API with the following scopes: ${outputToken.json(scopes)} `) - const envToken = getPartnersToken() + const envToken = getCliToken() if (envToken) { const result = await exchangeCustomPartnerToken(envToken) return {token: result.accessToken, userId: result.userId} @@ -141,7 +141,7 @@ export async function ensureAuthenticatedAppManagementAndBusinessPlatform( ${outputToken.json(appManagementScopes)} `) - const envToken = getPartnersToken() + const envToken = getCliToken() if (envToken) { const appManagmentToken = await exchangeCliTokenForAppManagementAccessToken(envToken) const businessPlatformToken = await exchangeCliTokenForBusinessPlatformAccessToken(envToken) From 0d99111b276dd664e5f1494b44a0693db7bf4b21 Mon Sep 17 00:00:00 2001 From: Gonzalo Riestra Date: Fri, 20 Mar 2026 14:52:26 +0100 Subject: [PATCH 2/2] Remove warning --- .changeset/heavy-adults-walk.md | 2 +- .../src/public/node/environment.test.ts | 23 +------------------ .../cli-kit/src/public/node/environment.ts | 19 --------------- .../cli-kit/src/public/node/hooks/prerun.ts | 2 -- 4 files changed, 2 insertions(+), 44 deletions(-) diff --git a/.changeset/heavy-adults-walk.md b/.changeset/heavy-adults-walk.md index cb20d31c124..b9b353fdf37 100644 --- a/.changeset/heavy-adults-walk.md +++ b/.changeset/heavy-adults-walk.md @@ -3,4 +3,4 @@ '@shopify/app': minor --- -Add support for SHOPIFY_CLI_TOKEN env var and add a deprecation warning for SHOPIFY_CLI_PARTNERS_TOKEN +Add support for SHOPIFY_CLI_TOKEN env var as a new name for SHOPIFY_CLI_PARTNERS_TOKEN diff --git a/packages/cli-kit/src/public/node/environment.test.ts b/packages/cli-kit/src/public/node/environment.test.ts index 2672fdb09c2..fb5239b5d4f 100644 --- a/packages/cli-kit/src/public/node/environment.test.ts +++ b/packages/cli-kit/src/public/node/environment.test.ts @@ -1,12 +1,8 @@ -import {getCliToken, showEnvVarDeprecationWarnings} from './environment.js' -import {mockAndCaptureOutput} from './testing/output.js' +import {getCliToken} from './environment.js' import {environmentVariables} from '../../private/node/constants.js' import {describe, expect, test, beforeEach} from 'vitest' -const outputMock = mockAndCaptureOutput() - beforeEach(() => { - outputMock.clear() delete process.env[environmentVariables.cliToken] delete process.env[environmentVariables.partnersToken] }) @@ -35,20 +31,3 @@ describe('getCliToken', () => { expect(getCliToken()).toBeUndefined() }) }) - -describe('showEnvVarDeprecationWarnings', () => { - test('shows warning when SHOPIFY_CLI_PARTNERS_TOKEN is set', () => { - process.env[environmentVariables.partnersToken] = 'old-token' - - showEnvVarDeprecationWarnings() - - expect(outputMock.warn()).toMatch(/SHOPIFY_CLI_PARTNERS_TOKEN/) - expect(outputMock.warn()).toMatch(/SHOPIFY_CLI_TOKEN/) - }) - - test('does not show warning when SHOPIFY_CLI_PARTNERS_TOKEN is not set', () => { - showEnvVarDeprecationWarnings() - - expect(outputMock.warn()).toBe('') - }) -}) diff --git a/packages/cli-kit/src/public/node/environment.ts b/packages/cli-kit/src/public/node/environment.ts index 6e12203ddf0..5044a732c9f 100644 --- a/packages/cli-kit/src/public/node/environment.ts +++ b/packages/cli-kit/src/public/node/environment.ts @@ -1,7 +1,6 @@ import {nonRandomUUID} from './crypto.js' import {isTruthy} from './context/utilities.js' import {sniffForJson} from './path.js' -import {renderWarning} from './ui.js' import {environmentVariables, systemEnvironmentVariables} from '../../private/node/constants.js' /** @@ -29,24 +28,6 @@ export function getCliToken(): string | undefined { return env[environmentVariables.cliToken] ?? env[environmentVariables.partnersToken] } -/** - * Shows deprecation warnings for environment variables that have been renamed. - * Currently warns when SHOPIFY_CLI_PARTNERS_TOKEN is used instead of SHOPIFY_CLI_TOKEN. - */ -export function showEnvVarDeprecationWarnings(): void { - const env = getEnvironmentVariables() - if (env[environmentVariables.partnersToken]) { - renderWarning({ - headline: [ - 'The environment variable', - {command: environmentVariables.partnersToken}, - 'has been deprecated and will eventually be removed.', - ], - body: ['Please use', {command: environmentVariables.cliToken}, 'instead.'], - }) - } -} - /** * Returns the value of the organization id from the environment variables. * diff --git a/packages/cli-kit/src/public/node/hooks/prerun.ts b/packages/cli-kit/src/public/node/hooks/prerun.ts index 9f3681bcbc7..b64c6c21cda 100644 --- a/packages/cli-kit/src/public/node/hooks/prerun.ts +++ b/packages/cli-kit/src/public/node/hooks/prerun.ts @@ -1,7 +1,6 @@ import {CLI_KIT_VERSION} from '../../common/version.js' import {checkForNewVersion, checkForCachedNewVersion} from '../node-package-manager.js' import {startAnalytics} from '../../../private/node/analytics.js' -import {showEnvVarDeprecationWarnings} from '../environment.js' import {outputDebug, outputWarn} from '../output.js' import {getOutputUpdateCLIReminder} from '../upgrade.js' import Command from '../base-command.js' @@ -24,7 +23,6 @@ export const hook: Hook.Prerun = async (options) => { }) const args = options.argv await warnOnAvailableUpgrade() - showEnvVarDeprecationWarnings() outputDebug(`Running command ${commandContent.command}`) await startAnalytics({commandContent, args, commandClass: options.Command as unknown as typeof Command}) fetchNotificationsInBackground(options.Command.id)