Big thank you to @KyleG-Shopify and @Dylan for your continued support and clear guidance throughout this troubleshooting journey! 
Your insights around:
- Enabling Storefront API in the Partner Dashboard
- Ensuring the correct unauthenticated access scopes
- Using
direct_api_mode = "offline"
and embedded_app_direct_api_access = true
…were exactly what I needed to resolve the ACCESS_DENIED
error when using the storefrontAccessTokenCreate
mutation.
Solution Summary
This .toml
config works for me when generating a Storefront Access Token:
# Learn more about configuring your app at https://shopify.dev/docs/apps/tools/cli/configuration
client_id = "xxxxx***####"
name = "Mobile App Builder"
handle = "mobile-app-cli-node"
application_url = "https://xxxxx***####.com/"
embedded = true
[api]
direct_api_mode = "offline"
embedded_app_direct_api_access = true
[build]
automatically_update_urls_on_dev = false
include_config_on_deploy = true
[webhooks]
api_version = "2025-04"
[[webhooks.subscriptions]]
uri = "/webhooks/customers/data_request"
compliance_topics = [ "customers/data_request" ]
[[webhooks.subscriptions]]
uri = "/webhooks/customers/redact"
compliance_topics = [ "customers/redact" ]
[[webhooks.subscriptions]]
uri = "/webhooks/shop/redact"
compliance_topics = [ "shop/redact" ]
[access_scopes]
scopes = "read_all_cart_transforms,read_all_orders,read_channels,read_checkouts,read_customer_events,read_customers,read_delivery_customizations,read_discovery,read_draft_orders,read_inventory,read_legal_policies,read_locales,read_locations,read_marketing_events,read_markets,read_order_edits,read_orders,read_product_listings,read_products,read_publications,read_shipping,read_translations,unauthenticated_read_checkouts,unauthenticated_read_customers,unauthenticated_read_product_listings,unauthenticated_write_checkouts,unauthenticated_write_customers,write_checkouts,write_customers,write_delivery_customizations,write_discovery,write_draft_orders,write_inventory,write_markets,write_order_edits,write_orders,write_payment_terms,write_product_listings,write_products,write_publications,write_translations"
[auth]
redirect_urls = [
"https://xxxxx***####.com//auth/callback",
"https://xxxxx***####.com//auth/shopify/callback",
"https://xxxxx***####.com//api/auth/callback"
]
[pos]
embedded = false
Use the Correct API Client
Does not work in:
- Shopify Admin GraphiQL (
admin/api/graphql
)
Works only in:
- GraphiQL API client inside a Remix Shopify CLI app project or Associate Shopify product
here is the e.g.
import { authenticate } from "../../../shopify.server";
/**
* Creates a new Storefront Access Token using Shopify's GraphQL API.
* @param {Request} request - The incoming request object (for authentication).
* @param {Object} input - The StorefrontAccessTokenInput object.
* @returns {Promise<Object>} The response from Shopify containing the access token or user errors.
*/
export const createStorefrontAccessToken = async (request, input) => {
const { admin } = await authenticate.admin(request);
const mutation = `
mutation storeFrontAccessTokenCreate($input: StorefrontAccessTokenInput!) {
storefrontAccessTokenCreate(input: $input) {
storefrontAccessToken {
id
accessToken
accessScopes {
handle
}
createdAt
title
}
userErrors {
field
message
}
}
}
`;
const variables = { input };
const response = await admin.graphql(mutation, { variables });
const result = await response.json();
return result.data?.storefrontAccessTokenCreate || {
storefrontAccessToken: null,
userErrors: [{ message: "No response from Shopify" }]
};
};
Notes:
storefrontAccessTokenCreate
requires an embedded app session with proper context — that’s why it only works in Remix-based CLI projects running via shopify app dev
.
- This is likely due to how Shopify enforces permission context and session token structure for that mutation.
- No extra scopes beyond unauthenticated Storefront API scopes are needed if your app is a Sales Channel.
- Keep
direct_api_mode = "offline"
to allow proper background access.
- In the Shopify Partner Dashboard, designate your app as a Sales Channel. This enables access to specific Storefront API features (if you are trying the checkout and cart apis).
Special Thanks
Massive thanks to @KyleG-Shopify and @Dylan for their insights and guidance throughout the troubleshooting. Your help navigating the tricky parts of Storefront API permissions is greatly appreciated!