shopify.auth.begin returns status code 410

Topic summary

A developer is encountering a 410 status code when calling shopify.auth.begin in a Next.js 13 application using the @shopify/shopify-api package.

Setup details:

  • Using ngrok tunnel for local development
  • Non-embedded app configuration
  • Middleware-based authentication flow
  • App and redirect URLs configured in Shopify Partner Dashboard

The error response:
Returns a Response object with status 410, empty body, and no redirect URL.

Key questions raised:

  • Which resource has been moved (410 typically indicates “Gone”)?
  • Is requesting an access token for every online store visitor the correct authentication approach?

Code provided includes:

  • Shopify API configuration with API version July24
  • Auth start endpoint handling
  • Middleware for session management
  • OAuth callback handler

The developer seeks guidance on resolving the 410 error and confirmation on their authentication implementation approach. Note: Some code snippets appear reversed/corrupted in the original post.

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

Hi

I am facing an issue with @Shopify_77 /shopify-api package in a nextJS 13 web application, when I start OAuth with the method shopify.auth.begin, it returns this object:

Response {
  status: 410,
  statusText: '',
  headers: Headers {},
  body: null,
  bodyUsed: false,
  ok: false,
  redirected: false,
  type: 'default',
  url: ''
}

Some context: I’m using ngrok to create a secure tunnel for my localhost to interact with my shopify store through a dashboard app that i’ve created only for the web application, I’ve set the app and redirect URLs in the partner dashboard and using the keys for the app in the config of shopify, with auto starting the auth session with a middleware.

As i understand it status code 410 means the resource has been moved, my question is which resource ? and is this the correct approach of authenticating an online store visitor ? every time having to request accessToken from shopify ?

see below code snippet for setup

shopify api config:

import {
  access_scopes,
  shopifyApiKey,
  appBaseUrl,
  shopifySecreteKey,
} from "@/enums";
import { ApiVersion, shopifyApi } from "@shopify/shopify-api";
import "@shopify/shopify-api/adapters/web-api";
import { restResources } from "@shopify/shopify-api/rest/admin/2024-07";

const shopify = shopifyApi({
  apiKey: shopifyApiKey,
  apiSecretKey: shopifySecreteKey,
  scopes: access_scopes,
  apiVersion: ApiVersion.July24,
  hostName: appBaseUrl,
  hostScheme: "https",
  isEmbeddedApp: false,
  restResources,
});

export default shopify;

Auth start:

import shopify from "@/lib/shopify";
import { NextRequest, NextResponse } from "next/server";

export async function GET(req: NextRequest, res: NextResponse) {
  const { searchParams } = new URL(req.url);
  const shop = searchParams.get("shop");

  if (!shop) {
    console.error("Shop parameter is missing");
    throw new Error("Shop parameter is missing");
  }

  try {
    const authRoute = await shopify.auth.begin({
      shop,
      callbackPath: "/api/auth/callback",
      isOnline: false,
      rawRequest: req,
      rawResponse: res,
    });

    console.log("auth route response: ", authRoute);
    return authRoute;
  } catch (error) {
    console.log("Error starting auth for shopify");
  }
}

auth callback:

import shopify from "@/lib/shopify";
import { cookies } from "next/headers";
import { NextRequest, NextResponse } from "next/server";

export async function GET(req: NextRequest, res: NextResponse) {
  try {
    const session = await shopify.auth.callback({
      rawRequest: req,
      rawResponse: res,
    });

    cookies().set("shopifySession", JSON.stringify(session), {
      httpOnly: true,
      secure: process.env.NODE_ENV === "production",
    });

    return NextResponse.redirect(new URL("/", req.url).toString());
  } catch (error) {
    console.error("Something went wrong in OAuth callback", error);
  }
}

middleware:

import { cookies } from "next/headers";
import { NextRequest, NextResponse } from "next/server";
import { appBaseUrl, shopifyShop } from "./enums";

export function middleware(req: NextRequest) {
  const shopifyCookieSession = cookies().get("shopifySession");

  if (!shopifyCookieSession) {
    const authRoute = new URL(
      `/api/auth/start?shop=${shopifyShop}`,
      appBaseUrl
    ).toString();

    try {
      fetch(authRoute).catch((error) => {
        console.error("Error in middleware auth start", error);
      });
    } catch (error) {
      console.error("Error running fetch in middleware");
      throw new Error("Error running fetch in middleware");
    }
  }

  return NextResponse.next();
}

export const config = {
  matcher: ["/((?!api/auth).*)"],
};

Would appreciate any advice or guidance on this :slightly_smiling_face: