[shopify-app-express]: validateAuthenticatedSession for non-embedded apps that make XHR requests

[shopify-app-express]: validateAuthenticatedSession for non-embedded apps that make XHR requests

Shopify Partner
6 0 2

See GitHub issue for full details.


We are building a straightforward application that leverages Shopify APIs on the backend.

After the initial installation and scope grant, we want to make subsequent (XHR/fetch) calls to the API that are instantiated by a user interaction in the frontend. For this purpose, we want to use a short-lived (online) access token as described by the docs:

Online access is meant to be used when a user is interacting with your app through the web, [...]

Example use case(s): Your app's security requirements specify short-lived access to a store. Tokens with online access mode expire either when the user logs out or after 24 hours.

To illustrate the use-case:

  1. User installs Shopify app, accepts grant, and is taken to our product landing page (self hosted; not embedded).
  2. At some point (any point) in the future, on the product landing page, the user can subscribe to a Billing Plan of their choosing.
  3. The "Subscribe" action (triggered by the user) makes a call to our backend (e.g. /api/pay?store={name}).
  4. The backend endpoint validates that the session is valid:
    4a. If valid, the route handlers makes the M2M call to Shopify's billing API, and respond accordingly
    4b. If not valid, the route handler results in a redirection to begin the authn/authz flow. Once authorized, they will then be redirected back to our product page, which should then automatically trigger the /api/pay?store={name} request again (this time with valid credentials).

For (4), on the surface, it would appear that this is specifically what the validateAuthenticatedSession is designed to do. The documentation suggests it should behave correctly for both embedded and non-embedded apps.

In the case where the user is authorized, the middleware works great. However, in the case where the session is invalid, the redirectOutOfApp function will result in a 302 to the auth endpoint. This tells the browser (who initialized the fetch() request) to redirect. The first redirect to the auth endpoint is fine, but then that route handler redirects to /admin/oauth/authorize on the shopify store domain. Since this is a cross-origin redirect, the browser fails due to CORS.

For the case of non-embedded apps that make XHR calls, it would be nice to have an out-of-the-box middleware, especially since the current middleware is 90% there.


Besides the need to be able to change the window.location, we would also need some special redirect handling, so that once the auth completes, the product page would then know to trigger the request initiated by step (3) "Subscribe" above. The only way we have figured out how to accomplish that, is by setting a cookie at request time that then gets propagated through, and can be read by the client when the transaction completes (per this post). But I do believe there is probably a better way.

I would also have expected this to be a fairly straightforward / common case (i.e. making credentialed requests via XHR in a non-embedded app), so I am surprised there is not something more well established. It would seem the App Bridge capability is tied to embedded apps w/ session tokens. This leads me to believe we may be missing something simple.



Replies 2 (2)

Shopify Staff
2807 310 805

Hi Jhelmer25,


Thanks for flagging this - will connect with the internal team who owns these packages.

Liam | Developer Advocate @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

Shopify Partner
6 0 2

Any updates @Liam?