Issue: Authenticated Checkout URL Not Working Using Public App Credentials (but Works with Dev App)

Hello @Dylan and everyone,

I’m facing an issue with authenticated checkout while using my public app (built using Appcraftly).
However, when I use a development app with the exact same access scopes, authenticated checkout works perfectly.


:white_check_mark: What I am trying to achieve:

  • Perform an authenticated checkout (checkout pre-filled with customer information) using a public app.

:white_check_mark: Access scopes used:

read_checkouts, write_checkouts, read_customers, write_customers, read_delivery_customizations, write_delivery_customizations, read_inventory, write_inventory, read_orders, write_orders, read_product_listings, write_product_listings, read_products, write_products, write_discovery, read_discovery, read_order_edits, write_order_edits, read_customer_events, write_payment_terms, read_publications, write_publications, read_markets, write_markets, read_translations, write_translations, read_all_orders, write_draft_orders, read_draft_orders, read_locations, read_marketing_events, read_channels, read_shipping, read_all_cart_transforms, read_legal_policies, read_locales, customer_read_customers, customer_write_customers, customer_read_orders, customer_write_orders, customer_read_locations

:cross_mark: Problem:

  • When using the public app, authenticated checkout fails.
  • When using the development app, authenticated checkout succeeds.

:hammer_and_wrench: Steps I’ve taken:

  • Confirmed the access scopes are identical between the public and development apps.
  • Verified the OAuth flow and token generation are working fine.
  • Checked Shopify documentation for any restrictions on public app vs dev app permissions but couldn’t find any related to this.

:red_question_mark: My Questions:

  1. Is there any additional configuration needed for authenticated checkout when using a public app?
  2. Are there specific scopes or settings in a public app that behave differently compared to a development app?
  3. Could it be related to app approval or sales channel publishing that’s required for checkout features?
  4. Has anyone else faced this issue while migrating from a development to a public app?

Any help or guidance would be really appreciated!

Thanks in advance! :folded_hands:




Could you share exactly what the failure is?

Is is a failed API request? Or some error displayed in the checkout UI?

What is the problem exactly?

Hi @Dylan,

Thanks for respnse

We’re building a mobile app using the Store’s custom app (development app).
We are using only the Storefront API credentials (specifically, the storefront access token).

  • With the dev app, we are able to do login, signup, unauthenticated checkout (via GraphQL cart mutations), and even authenticated checkout (checkout prefilled with customer information).
  • For admin-side queries (orders, customers, etc.), we are using a separate public app via Admin GraphQL API.

The problem happens only when switching to the public app:

  • When trying to perform an authenticated checkout (by passing customerAccessToken inside the buyerIdentity during cartCreate mutation), it fails with this error:

json

CopyEdit

[
  {
    "code": "INVALID",
    "field": ["input", "buyerIdentity", "customerAccessToken"],
    "message": "Customer is invalid"
  }
]

However:

  • The customerAccessToken is verified — we are able to fetch customer data using the same token successfully.
  • Unauthenticated checkout (checkout without pre-filled with customer information ) works fine even with the public app.

:hammer: Steps we already tried:

  • Confirmed access scopes (like read_customers, read_checkouts) are identical between the public and development apps.
  • Verified the OAuth flow and token generation.
  • Reviewed Shopify docs but didn’t find any mention of special restrictions for public apps here.

:red_question_mark: Questions:

  • Is there any extra setup needed to support authenticated checkout when moving from a dev app to a public app?
  • Are there special scopes, app settings, or sales channel requirements that apply only to public apps?
  • Could this be related to app approval, or that the public app must be “published” as a sales channel for full checkout capabilities?
  • Has anyone else encountered this issue when migrating from a dev app to a public app?

This is the Cart mutation im using

let raw = {
      query: mutation cartCreate($lines: [CartLineInput!]!, $buyerIdentity: CartBuyerIdentityInput, $discountCodes: [String!]!) @inContext(country: ${country}, language: ${language}) {
        cartCreate(input: {lines: $lines, buyerIdentity: $buyerIdentity, discountCodes: $discountCodes}) {
          cart {
            checkoutUrl
            id
            note
            totalQuantity
            updatedAt
            createdAt
            discountCodes {
              applicable
              code
            }
            
            cost {
              checkoutChargeAmount {
                amount
                currencyCode
              }
              subtotalAmount {
                amount
                currencyCode
              }
              subtotalAmountEstimated
              totalAmount {
                amount
                currencyCode
              }
              totalAmountEstimated
              totalDutyAmount {
                amount
                currencyCode
              }
              totalDutyAmountEstimated
              totalTaxAmount {
                amount
                currencyCode
              }
              totalTaxAmountEstimated
            }
            lines(first: 10) {
              nodes {
                id
                quantity
                cost {
                  amountPerQuantity {
                    amount
                    currencyCode
                  }
                  compareAtAmountPerQuantity {
                    amount
                    currencyCode
                  }
                  subtotalAmount {
                    amount
                    currencyCode
                  }
                  totalAmount {
                    amount
                    currencyCode
                  }
                }
                
                merchandise {
                  ... on ProductVariant {
                    id
                    availableForSale
                    quantityAvailable
                    title
                    weight
                    selectedOptions {
                      name
                      value
                    }
                    price {
                      amount
                      currencyCode
                    }
                    currentlyNotInStock
                    product {
                      availableForSale
                      id
                      featuredImage {
                        id
                        url
                      }
                      title
                      vendor
                      totalInventory
                    }
                  }
                }
              }
              pageInfo {
                endCursor
                hasNextPage
                hasPreviousPage
                startCursor
              }
            }
          } 
          userErrors {
            code
            field
            message
          }
        }
      },
      variables: {
        lines: mergedItems,
        buyerIdentity: {
          email: email ?? null,
          customerAccessToken: customerAccessToken ?? null,
        },
        discountCodes: discountCodes,
      },
    };

    let requestOptions = {
      method: 'POST',
      headers: myHeaders,
      body: JSON.stringify(raw),
      redirect: 'follow',
    };

    const response = await fetch(
      https://${AppConfig.SHOP_URL}/api/2024-04/graphql.json,
      requestOptions,
    );
    if (!response.ok) {
      throw new Error(HTTP error! Status: ${response.status});
    }

    const result = await response.json();
    return result;
  } 


Thanks again for your help! Let me know if you need any more technical details or GraphQL snippets.

Hmm, maybe it’s a bug within the cartCreate Online Store access token.

Does the response include any headers with UUIDs for reference? Sharing those might help Shopifolk with server log access to troubleshoot further.

I’ve also recategorized your post to the Storefront APIs category, so it’s visible to the correct Shopify team.