[Prototype] Authenticate CLI with organization automation tokens - #8597
Draft
alexanderMontague wants to merge 3 commits into
Draft
alexanderMontague wants to merge 3 commits into
alexanderMontague wants to merge 3 commits into
Conversation
Business Platform commands could not run with SHOPIFY_APP_AUTOMATION_TOKEN
set. ensureAuthenticated() only exchanged the environment token when
applications.partnersApi was requested, so a BP-only command fell through
to the device authorization flow and failed on throwOnNoPrompt in any
non-interactive environment. ensureAuthenticatedBusinessPlatform() now
exchanges the environment token directly, matching what
ensureAuthenticatedPartners() and ensureAuthenticatedAppManagement()
already do.
The exchange also stops asking for scopes. It previously requested
destinations.readonly, and widening that to include
organization.store-management for organization-scoped tokens turned out
to break app-scoped ones: Identity refuses to grant a scope the subject
token does not already hold, so an app-scoped token was rejected with
invalid_request :: Invalid 'scope' value: new scopes must not be
specified
Requesting no scope makes Identity grant whatever the token carries,
narrowed to Business Platform. An organization-scoped token comes back
with store management and an app-scoped token does not, which is the
distinction we want, and neither has to be special-cased here. An empty
scope string behaves the same as omitting the parameter, so
requestAppToken() needs no change.
Verified against local Identity with both token kinds: `organization list`
and `store list` work with either, and `store create dev` authenticates
with an organization-scoped token. An app-scoped token authenticates but
is refused by Business Platform for store management, as intended.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Assisted-By: devx/f5485e0b-dc2b-4459-9b5d-7968b926fcfb
Select organization, app, and deprecated Partners automation tokens through one canonical helper, reject ambiguous organization/app credentials, and keep automation exchanges authoritative for Business Platform and App Management retries.
Contributor
Differences in type declarationsWe detected differences in the type declarations generated by Typescript for this branch compared to the baseline ('main' branch). Please, review them to ensure they are backward-compatible. Here are some important things to keep in mind:
New type declarationsWe found no new type declarations in this PR Existing type declarationspackages/cli-kit/dist/private/node/constants.d.ts@@ -8,6 +8,7 @@ export declare const environmentVariables: {
env: string;
noAnalytics: string;
optOutInstrumentation: string;
+ organizationAutomationToken: string;
appAutomationToken: string;
partnersToken: string;
runAsUser: string;
packages/cli-kit/dist/private/node/session.d.ts@@ -104,5 +104,5 @@ export interface EnsureAuthenticatedAdditionalOptions {
* @param options - Optional extra options to use.
* @returns An instance with the access tokens organized by application.
*/
-export declare function ensureAuthenticated(applications: OAuthApplications, _env?: NodeJS.ProcessEnv, { forceRefresh, noPrompt, forceNewSession }?: EnsureAuthenticatedAdditionalOptions): Promise<OAuthSession>;
+export declare function ensureAuthenticated(applications: OAuthApplications, env?: NodeJS.ProcessEnv, { forceRefresh, noPrompt, forceNewSession }?: EnsureAuthenticatedAdditionalOptions): Promise<OAuthSession>;
export {};
\ No newline at end of file
packages/cli-kit/dist/public/node/environment.d.ts@@ -9,11 +9,27 @@
* @returns Current process environment variables.
*/
export declare function getEnvironmentVariables(): NodeJS.ProcessEnv;
+export interface AutomationToken {
+ value: string;
+ source: 'organization' | 'app' | 'partners';
+}
/**
- * Returns the value of the SHOPIFY_APP_AUTOMATION_TOKEN environment variable,
- * falling back to the deprecated SHOPIFY_CLI_PARTNERS_TOKEN.
+ * Selects the automation token to use for authentication.
*
- * @returns The app automation token value, or undefined if neither env var is set.
+ * Organization and app automation tokens are mutually exclusive because they represent different
+ * authentication subjects. The deprecated Partners token remains a fallback for compatibility.
+ *
+ * @param env - Environment variables to select the token from.
+ * @returns The selected automation token and its source, or undefined if none is set.
+ * @throws AbortError when both organization and app automation tokens are set.
+ */
+export declare function getAutomationToken(env?: NodeJS.ProcessEnv): AutomationToken | undefined;
+/**
+ * Returns the selected automation token value.
+ *
+ * Prefer getAutomationToken when the token source is needed.
+ *
+ * @returns The selected automation token value, or undefined if none is set.
*/
export declare function getAppAutomationToken(): string | undefined;
/**
packages/cli-kit/dist/public/node/session.d.ts@@ -72,8 +72,8 @@ export declare function ensureAuthenticatedUser(env?: NodeJS.ProcessEnv, options
}>;
/**
* Ensure that we have a valid session to access the Partners API.
- * If SHOPIFY_CLI_PARTNERS_TOKEN exists, that token will be used to obtain a valid Partners Token
- * If SHOPIFY_CLI_PARTNERS_TOKEN exists, scopes will be ignored.
+ * If an automation token exists in the environment, it will be used to obtain a valid Partners token
+ * and scopes will be ignored.
*
* @param scopes - Optional array of extra scopes to authenticate with.
* @param env - Optional environment variables to use.
@@ -130,6 +130,7 @@ export declare function ensureAuthenticatedAdmin(store: string, scopes?: AdminAP
export declare function ensureAuthenticatedThemes(store: string, password: string | undefined, scopes?: AdminAPIScope[], options?: EnsureAuthenticatedAdditionalOptions): Promise<AdminSession>;
/**
* Ensure that we have a valid session to access the Business Platform API.
+ * If an automation token exists in the environment, that token will be used and scopes will be ignored.
*
* @param scopes - Optional array of extra scopes to authenticate with.
* @param options - Optional extra options to use.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds unattended authentication for organization-scoped automation credentials issued by the accompanying World prototype.
SHOPIFY_ORGANIZATION_AUTOMATION_TOKENis a first-class, mutually exclusive credential source. Supported Business Platform and App Management paths exchange it directly; unsupported commands fail instead of silently using cached or interactive human authentication. Organization discovery uses the Business Platform Destinations path through@shopify/organizations, so store-only service accounts do not need an app-management grant merely to find their organization and owned development stores.Live local evidence against the World services:
organization list --jsonreturned the service account’s organization;store list --organization-id 1 --jsonreturned two development stores owned by that service account;Open questions for production planning:
Validation: 129 focused Vitest tests pass;
@shopify/cli-kitand@shopify/apptypechecks pass; ESLint passes for every changed TypeScript file.Generated with Pi. Vetted by Me.