Running graphql on Shopify Flow action

Topic summary

Issue Identified:
Developers encountered a 401 status error when attempting to run GraphQL queries within Shopify Flow actions, stemming from authentication failures.

Solution - Route Placement:

  • The action route must be placed under the app directory (e.g., app/routes/app/api/action.js)
  • Routes outside this structure fail GraphQL authentication with “Invalid API key or access token” errors

Solution - HMAC Validation:

  • Implement HMAC-SHA256 validation using the X-Shopify-Hmac-SHA256 header
  • Use unauthenticated from shopify.server instead of standard authenticate.admin
  • Validate the request signature against SHOPIFY_API_SECRET before processing

Key Code Requirements:

  • Extract raw request body for HMAC comparison
  • Verify HMAC matches before executing GraphQL queries
  • Use unauthenticated(request).admin(shop_domain) for proper authentication context

Documentation Reference:
The official solution is documented at shopify.dev/docs/api/shopify-app-remix/v2/authenticate/flow, though this wasn’t clearly linked in the Flow action extension docs initially.

Summarized with AI on November 10. AI used: claude-sonnet-4-5-20250929.

Has anyone tried to run a Graphql query on Shopify Flow action?

Below is from action.jsx code:

export const action = async ({request}) => {
  const { admin } = await authenticate.admin(request);
  const body = await request.json();
  return json({body});
}

I got status 410 error.

I need to validate a request, but I don’t know how to do that.
https://shopify.dev/docs/apps/flow/actions/create-an-action#verifying-requests

The following code could be used to do this.

Note that the route of the process to be called should be under app.

Example: app-directory/app/routes/app/api/action.js

Otherwise, Graphql will not be authenticated and the error “[API] Invalid API key or access token (unrecognized login or wrong password)” will occur.

import { unauthenticated } from "~/shopify.server";
// Includes crypto module
const crypto = require("crypto");

export const action = async ({ request }) => {
  // Hmac validation
  const rawBody = await request.text();
  const hmacHeader = request.headers.get("X-Shopify-Hmac-SHA256");
  const hmac = await crypto.createHmac("sha256", process?.env?.SHOPIFY_API_SECRET);
  const hash = await hmac.update(rawBody, "utf8").digest("base64");
  // console.log("signature match : " + (hash == hmacHeader));
  if(hash !== hmacHeader) {
    return new Response(undefined, {
      status: 401,
      statusText: 'Unauthorized'
    });
  }

  const data = JSON.parse(rawBody);
  if(data.handle !== "handle") {
    return new Response(undefined, {
      status: 405,
      statusText: 'Method Not Allowed'
    });
  }

  const { admin } = await unauthenticated.admin(data.shopify_domain);
  const response = await admin.graphql(
   `#graphql
      query {
        shop{
         name
        }
      }
  }`);
  const responseJson = await response.json();
  console.log(responseJson);
  return null;
};

If anyone else is having this issue, I found this link in the shopify remix docs which solved all my problems with authenticating flow request: https://shopify.dev/docs/api/shopify-app-remix/v2/authenticate/flow
This wasn’t linked on the flow action extension docs anywhere so it was a bit withheld.

1 Like