I tested Checkout MCP both with and without authentication:
- Without an
Authorization header, create_checkout works successfully.
- With an authenticated bearer token, the same request fails with HTTP 401 and
AuthenticationFailed.
I tested two token types:
-
A token created through the Dev Dashboard Catalogs flow. It contains:
read_global_api_catalog_search
write_global_api_app_events
-
A token created using credentials from a newly created app. It contains:
write_global_api_app_events
Both tokens were minted successfully using the documented client-credentials endpoint:
POST https://api.shopify.com/auth/access_token
However, Checkout MCP rejects both authenticated requests. Removing the bearer token makes the identical request succeed.
Could you confirm what app configuration or token claim is required for authenticated Checkout MCP access?
Hi @Ahmed_Osman, I had a look for you. The unauthenticated call succeeding is actually expected behavior. Checkout tools are reachable at all three traffic tiers (Token, Signed, and Anonymous), so create_checkout works without an Authorization header. Authentication at the Token tier is mainly what unlocks higher rate limits plus the sensitive tools like complete_checkout and order reads. The tier breakdown is here: Auth and rate limiting.
On the 401s, since both a Dev Dashboard Catalogs token and a plain app credentials token fail the same way, which suggests the credential itself not being accepted for this endpoint rather than a missing permission on create_checkout.
The only scopes the tier table ties to checkout flows are for complete_checkout and order reads, and write_global_api_app_events isn’t one of those.
To narrow down what’s rejecting the token, can you share:
- The full JSON-RPC error response, including the
data field (the exact string after AuthenticationFailed matters)
- The exact MCP endpoint URL you’re posting to
- The client ID the token was minted from (you can share this via DM if you prefer, let me know and I’ll ping you!), and roughly when the failing calls were made (UTC)
Also worth double-checking the token is sent exactly as Authorization: Bearer {token} with no extra prefix, and that it’s still within its lifetime when the call is made. Thanks!
Thanks for pointing us toward the full error.data field. We reproduced the request with expanded diagnostics and identified the cause.
Two separately minted, unexpired Catalog bearer tokens produced the same response when calling create_checkout :
"error": {
"code": -32000,
"message": "AuthenticationFailed",
"data": "Missing required buyer IP header."
}
}
We then repeated the same request with a Shopify-Storefront-Buyer-IP header, and the authenticated call succeeded with HTTP 200. The same request also continued to succeed anonymously without that header. This confirms that the bearer token and its scopes were valid; the failure was caused by the missing buyer-IP header.
Could you clarify if it’s expected? We currently do not track customer IPs