Skip to content

Conversation

@ericlee878
Copy link
Contributor

@ericlee878 ericlee878 commented Nov 19, 2025

Resolves: https://github.com/orgs/shop/projects/208/views/34?pane=issue&itemId=140363951&issue=shop%7Cissues-api-foundations%7C1128
Inspired by: #6596 (comment)

Background

The bulk operations execute command currently authenticates using the CLI user's credentials, which has two critical limitations:

  1. No access to $app metafields - Cannot query or mutate app-specific metafields
  2. Ignores app scopes - Does not respect the app's configured access scopes.

This prevents bulk operations from working properly with app-owned data.

Solution

Implemented ensureAuthenticatedAdminAsApp() that authenticates as the app using OAuth 2.0 client credentials grant. This provides:

  • Full access to $app metafields
  • Respects the app's configured scopes
  • Proper app-context authentication

This idea originally came from a hack days.

EDIT: Actually #6649 beat us to it! This PR now just adjusts app execute to use this feature, and doesn't have to implement it itself.

Implementation Notes

  • The API secret extraction pattern follows the existing approach in webhook/trigger-options.ts.
  • Currently both app and remoteApp are passed to executeBulkOperation. The app parameter is only used for:
    • Display name (app.name)
    • Client ID (app.configuration.client_id)

Both values are also available on remoteApp as title and apiKey. Could be simplified in the future to only use remoteApp for consistency.

Testing

To test with this new authentification, you must install the app on the store. You can do this by:

cd <PATH_TO_TEST_APP>
pnpm shopify app dev

Then, we can use the existing command works unchanged:

For queries:

pnpm shopify:run app execute \
  --path <PATH_TO_TEST_APPP> \
  -q '{ products(first: 10) { edges { node { id title } } } }'

For mutations:

pnpm shopify:run app execute \
  --path <PATH_TO_TEST_APPP> \
  -q 'mutation productUpdate($input: ProductInput!) { productUpdate(input: $input) { product { id tags } userErrors { field message } } }' \
  -v '[{"input": {"id": "gid://shopify/Product/9721830834416", "tags": ["bulk-test"]}}]'

Now authenticates as the app instead of the CLI user, enabling access to app-scoped resources.

@ericlee878 ericlee878 changed the title implement-ensureAuthenticatedAdminAsApp-for-BulkOps-CLI Implement ensureAuthenticatedAdminAsApp for Bulk Operations Nov 19, 2025
Copy link
Contributor Author

ericlee878 commented Nov 19, 2025

@github-actions
Copy link
Contributor

github-actions bot commented Nov 19, 2025

Coverage report

St.
Category Percentage Covered / Total
🟡 Statements
79.27% (+0.04% 🔼)
13725/17314
🟡 Branches
73.17% (+0.06% 🔼)
6699/9155
🟡 Functions
79.42% (+0.04% 🔼)
3530/4445
🟡 Lines
79.64% (+0.06% 🔼)
12970/16286
Show new covered files 🐣
St.
File Statements Branches Functions Lines
🟢
... / admin-as-app.ts
100% 100% 100% 100%
🟢
... / bulk-operation-run-mutation.ts
100% 100% 100% 100%
🟢
... / bulk-operation-run-query.ts
100% 100% 100% 100%
🟢
... / get-bulk-operation-by-id.ts
100% 100% 100% 100%
🟢
... / staged-uploads-create.ts
100% 100% 100% 100%
🟢
... / download-bulk-operation-results.ts
100% 100% 100% 100%
🟢
... / execute-bulk-operation.ts
90.91% 80.56% 100% 92.31%
🟢
... / format-bulk-operation-status.ts
100% 100% 100% 100%
🟢
... / run-mutation.ts
100% 100% 100% 100%
🟢
... / run-query.ts
100% 100% 100% 100%
🟡
... / stage-file.ts
72.73% 62.5% 83.33% 71.88%
🟢
... / watch-bulk-operation.ts
100% 100% 100% 100%
Show files with reduced coverage 🔻
St.
File Statements Branches Functions Lines
🟡
... / specification.ts
68.52% (-0.57% 🔻)
75.61% (+2.44% 🔼)
76.47% (-1.31% 🔻)
68.09% (-0.66% 🔻)
🟢
... / developer-platform-client.ts
84.62% (-1.5% 🔻)
73.68% (+3.1% 🔼)
81.82% (+1.82% 🔼)
90.63% (-2.71% 🔻)
🟢
... / api.ts
87.07% (-0.43% 🔻)
76.71% (-0.1% 🔻)
100%
86.49% (-0.43% 🔻)
🟢
... / ConcurrentOutput.tsx
98.36% (-1.64% 🔻)
92% (-4% 🔻)
100%
98.33% (-1.67% 🔻)
🔴
... / ui.tsx
50.82% (-0.79% 🔻)
42.86% (-5.53% 🔻)
54.55% (+1.42% 🔼)
50% (-0.82% 🔻)
🟢
... / console.ts
81.82% (+15.15% 🔼)
75% (-25% 🔻)
100% (+33.33% 🔼)
81.82% (+15.15% 🔼)
🔴
... / dev.ts
12.77% (-0.57% 🔻)
2.78% (-0.16% 🔻)
57.14%
12.77% (-0.57% 🔻)
🟡
... / theme-environment.ts
69.57% (-1.86% 🔻)
50%
55.56% (-3.27% 🔻)
69.57% (-1.86% 🔻)

Test suite run success

3406 tests passing in 1386 suites.

Report generated by 🧪jest coverage report action from 02b54ed

@ericlee878 ericlee878 marked this pull request as ready for review November 19, 2025 23:56
@ericlee878 ericlee878 requested a review from a team as a code owner November 19, 2025 23:56
@github-actions
Copy link
Contributor

We detected some changes at packages/*/src and there are no updates in the .changeset.
If the changes are user-facing, run pnpm changeset add to track your changes and include them in the next release CHANGELOG.

Caution

DO NOT create changesets for features which you do not wish to be included in the public changelog of the next CLI release.

Copy link
Contributor

@nickwesselman nickwesselman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would like both CLI and someone w/ knowledge of app access to confirm this approach but this meets the Product requirements 👍🏻

@ericlee878 ericlee878 force-pushed the 11-18-implement-variable-file-flag branch from 2c2b13c to 691d000 Compare November 20, 2025 17:57
@ericlee878 ericlee878 force-pushed the 11-19-implement-ensureAuthenticatedAdminAsApp branch 2 times, most recently from f5e87ce to 0e7b765 Compare November 20, 2025 18:00
@ericlee878 ericlee878 force-pushed the 11-18-implement-variable-file-flag branch 2 times, most recently from 204edc8 to 028510c Compare November 20, 2025 18:24
@ericlee878 ericlee878 force-pushed the 11-19-implement-ensureAuthenticatedAdminAsApp branch from 0e7b765 to 53eb2f0 Compare November 20, 2025 18:24
@ericlee878 ericlee878 force-pushed the 11-18-implement-variable-file-flag branch from 028510c to c6078b1 Compare November 20, 2025 19:46
@ericlee878 ericlee878 force-pushed the 11-19-implement-ensureAuthenticatedAdminAsApp branch from 53eb2f0 to 06be306 Compare November 20, 2025 19:46
@github-actions
Copy link
Contributor

Differences in type declarations

We 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:

  • Some seemingly private modules might be re-exported through public modules.
  • If the branch is behind main you might see odd diffs, rebase main into this branch.

New type declarations

We found no new type declarations in this PR

Existing type declarations

packages/cli-kit/dist/public/node/session.d.ts
@@ -97,6 +97,17 @@ export declare function ensureAuthenticatedStorefront(scopes?: StorefrontRendere
  * @returns The access token for the Admin API.
  */
 export declare function ensureAuthenticatedAdmin(store: string, scopes?: AdminAPIScope[], options?: EnsureAuthenticatedAdditionalOptions): Promise<AdminSession>;
+/**
+ * Ensure that we have a valid Admin session for the given store, acting on behalf of the app.
+ *
+ * This will fail if the app has not already been installed.
+ *
+ * @param storeFqdn - Store fqdn to request auth for.
+ * @param apiKey - API key for the app.
+ * @param apiSecret - API secret for the app.
+ * @returns The access token for the Admin API.
+ */
+export declare function ensureAuthenticatedAdminAsApp(storeFqdn: string, apiKey: string, apiSecret: string): Promise<AdminSession>;
 /**
  * Ensure that we have a valid session to access the Theme API.
  * If a password is provided, that token will be used against Theme Access API.

Base automatically changed from 11-18-implement-variable-file-flag to main November 24, 2025 17:15
Copy link
Contributor

@RyanDJLee RyanDJLee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes make sense to me, but let's make sure we do not expose the access token before we ship.

@ericlee878 ericlee878 force-pushed the 11-19-implement-ensureAuthenticatedAdminAsApp branch 2 times, most recently from f9b53e2 to e9bb7f5 Compare November 24, 2025 18:43

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const apiSecret = remoteApp.apiSecretKeys.find((elm) => elm.secret)!.secret
const adminSession = await ensureAuthenticatedAdminAsApp(storeFqdn, app.configuration.client_id, apiSecret)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What actually is a remote app? It seems odd to me to set up a session using the client ID from app but the API secret from remoteApp... but I'm guessing this is correct for some complicated reason. Can you explain?

Copy link
Contributor

@jordanverasamy jordanverasamy Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see this from the PR desc:

Both values are also available on remoteApp as title and apiKey. Could be simplified in the future to only use remoteApp for consistency.

Maybe we should adjust it to use remoteApp all the way through for consistency and to minimize confusion, if possible? How big of a lift is that you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept it for consistency. All other CLI's used app. Didn't seem like it would hurt to keep it in there?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remoteApp is the remote representation of the App obtained via the API. The secret can only be obtained from the remoteApp, is not available in the "local" app

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use remoteApp​ to access the client_id value too yes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed app and using remoteApp for everything.

Copy link
Contributor

@jordanverasamy jordanverasamy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming that this is all following the directions from app access, this PR seems reasonable to me, but I don't currently understand deeply enough to have a meaningful ✅ .

@graphite-app
Copy link

graphite-app bot commented Nov 26, 2025

Merge activity

  • Nov 26, 7:37 PM UTC: This pull request can not be added to the Graphite merge queue. Please try rebasing and resubmitting to merge when ready.
  • Nov 26, 7:37 PM UTC: Graphite disabled "merge when ready" on this PR due to: a merge conflict with the target branch; resolve the conflict and try again..

@jordanverasamy jordanverasamy force-pushed the 11-19-implement-ensureAuthenticatedAdminAsApp branch from a0b57c8 to 386074f Compare November 27, 2025 03:45
@jordanverasamy jordanverasamy force-pushed the 11-19-implement-ensureAuthenticatedAdminAsApp branch from 386074f to 479bccb Compare November 27, 2025 03:51
Copy link
Contributor

@gonzaloriestra gonzaloriestra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to say that ensureAuthenticatedAdminAsApp was already added by #6649, but I guess you already realized, no?

The description is outdated, but the changes make sense.

@jordanverasamy jordanverasamy force-pushed the 11-19-implement-ensureAuthenticatedAdminAsApp branch from 479bccb to 8fc9ddf Compare November 27, 2025 16:30
@jordanverasamy
Copy link
Contributor

Yeah, sorry for the outdated description -- I'll update at least the title so it'll be clearer to future readers what this PR is actually doing.

Thanks for the quick review!

@jordanverasamy jordanverasamy changed the title Implement ensureAuthenticatedAdminAsApp for Bulk Operations Use ensureAuthenticatedAdminAsApp in shopify app execute Nov 27, 2025
@jordanverasamy jordanverasamy force-pushed the 11-19-implement-ensureAuthenticatedAdminAsApp branch from 41d68b3 to 02b54ed Compare November 27, 2025 17:22
@jordanverasamy jordanverasamy added this pull request to the merge queue Nov 27, 2025
Merged via the queue into main with commit 70c69c7 Nov 27, 2025
25 checks passed
@jordanverasamy jordanverasamy deleted the 11-19-implement-ensureAuthenticatedAdminAsApp branch November 27, 2025 17:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants