Authentication problem when working with Webhook and GraphQL

Topic summary

A developer is encountering a 401 Unauthorized error when attempting to use GraphQL within a Shopify webhook handler. The goal is to automatically delete a product with a specific SKU when an order is created.

The Problem:

  • Initial webhook setup worked correctly (returned status 200)
  • Authentication fails when trying to execute GraphQL mutations from within the webhook
  • Using authenticate.admin(request) doesn’t work because no session is available in webhook context
  • Switching to authenticate.webhook(request) triggers the 401 error

Technical Details:

  • The code attempts to query products by SKU and delete them using GraphQL mutations
  • Developer is manually constructing a session object using environment variables (SHOP_CUSTOM_DOMAIN, SHOPIFY_ADMIN_ACCESS_TOKEN)
  • The webhook is configured in Shopify admin but GraphQL client authentication is failing

Current Status:

  • Issue remains unresolved
  • A second developer has reported experiencing the identical problem
  • No solution or workaround has been identified yet
Summarized with AI on October 27. AI used: claude-sonnet-4-5-20250929.

when creating the webhook in the admin shopifai and also connecting to it and there were no problems gave out the status 200 and also displayed logs in the console, which I wrote myself in the application remix.
but I need that when the event of order creation occurs the product with a certain sku was deleted, and for this I need to work with graphql and for working with it I need authentication I tried through

“const { admin } = await authenticate.admin(request);”

but it turned out that I can’t do that because I can’t get the session from anywhere and I started to use

“const { shop, payload, topic } = await authenticate.webhook(request);”

and after that the error “status: 401, statusText: ‘Unauthorized’,” started to appear.

import { json } from "@remix-run/node";
import { authenticate } from "../shopify.server";
import { shopifyApi } from "@shopify/shopify-api";
import prisma from "../db.server";

export const action = async ({ request }) => {
  try {
    const { shop, payload, topic } = await authenticate.webhook(request);

    const lineItems = payload.line_items;

    if (!lineItems || lineItems.length === 0) {
      return json({ error: "No items in the order" }, { status: 400 });
    }

    const sku = lineItems[0].sku;

    if (!sku) {
      return json({ error: "SKU not found in order data" }, { status: 400 });
    }

    const session = {
      shop: process.env.SHOP_CUSTOM_DOMAIN,
      accessToken: process.env.SHOPIFY_ADMIN_API_ACCESS_TOKEN,
    };

    const client = new shopifyApi.clients.Graphql({ session });

    const query = `
      query($sku: String!) {
        productVariants(first: 1, query: $sku) {
          edges {
            node {
              id
              product {
                id
              }
            }
          }
        }
      }
    `;

    const variables = { sku: `sku:${sku}` };

    const response = await client.query({
      data: {
        query,
        variables,
      },
    });

    const variant = response.body.data.productVariants.edges[0]?.node;
    if (!variant) {
      return json(
        { error: "Product with the specified SKU not found" },
        { status: 404 },
      );
    }

    const productId = variant.product.id;

    const mutation = `
      mutation($input: ProductDeleteInput!) {
        productDelete(input: $input) {
          deletedProductId
          userErrors {
            field
            message
          }
        }
      }
    `;

    const mutationVariables = { input: { id: productId } };

    const deleteResponse = await client.query({
      data: {
        query: mutation,
        variables: mutationVariables,
      },
    });

    if (
      deleteResponse.body.data.productDelete.userErrors &&
      deleteResponse.body.data.productDelete.userErrors.length > 0
    ) {
      const errorMessage =
        deleteResponse.body.data.productDelete.userErrors[0].message;
      return json({ error: errorMessage }, { status: 400 });
    }

    return json({ success: true }, { status: 200 });
  } catch (error) {
    return json({ success: false, error: error.message }, { status: 400 });
  }
};
1 Like

Have you resolved this issue? I have exactly the same problem, and I am trying to find a solution.