Authenticated API request using new method for embedded apps

AI-generated summary

Issue: A Checkout PostPurchase extension cannot make an authenticated POST to the app’s API; the fetch to /api/offer returns a 302 redirect to a login page, implying the request is treated as unauthenticated.

Context:

  • Goal: Query Products and show an offer post‑purchase. The extension fetches ${APP_URL}/api/offer with JSON body (referenceId) and stores the response in extension storage.
  • App uses Shopify CLI and follows the new embedded auth strategy for Remix (linked docs).

Server route (Remix):

  • Loader: uses authenticate.public.checkout(request) (for Shopify preflight/CORS) and also calls shopify.authenticate.admin(request), then returns cors({ ok: true }).
  • Action: uses authenticate.admin(request) and returns JSON.

Key concern:

  • How to correctly authenticate extension-originated requests to this route so they are not redirected to login. There may be a mismatch between public.checkout and admin authentication for this context.

Status: Unresolved; seeking guidance. Code snippets and a screenshot of the 302 redirect are central to understanding.

Hi,

I am creating an app that will extend Checkout::PostPurchase. I am having trouble making initial calls to my API.

Ultimately, I want to query my Products table and display a product pust purchase. However, I cannot seem to make an authenicated request to my server. Here is my relevant code from my extension’s index file:

extend(
  "Checkout::PostPurchase::ShouldRender",
  async ({ inputData, storage }) => {
    const postPurchaseOffer = await fetch(`${APP_URL}/api/offer`, {
        method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        referenceId: inputData.initialPurchase.referenceId,
      }),
    }).then((response) => response.json());

    console.log('postoffer', postPurchaseOffer);

    // Store the offer in the extension's storage.
    await storage.update(postPurchaseOffer);

    // For local development, always show the post-purchase page
    return { render: true };
  }
);

When I make this fetch call, the call to api/offer responds with 302 Redirected. It seems my api call is being redirected to a page called login.

Screenshot from 2024-03-11 13-46-07.png

I am following this documentation which explains a new way of authenticating api requests. My app is managed through shopify cli, and i’ve added the necessary configs to my shopify app initialization.

How canI make an authenticated request to mmy shopify api route. Here is the route I want to hit ultimately:

import { authenticate } from "../shopify.server";
import shopify from "../shopify.server";
import { json } from "@remix-run/node";
// The loader responds to preflight requests from Shopify
export const loader = async ({ request }) => {
  console.log('in loader');
 const { cors } = await authenticate.public.checkout(request);
  const { admin } = await shopify.authenticate.admin(request);

  return cors({
    ok: true,
    message: 'hello'
  })
};

// The action responds to the POST request from the extension. Make sure to use the cors helper for the request to work.
export const action = async ({ request }) => {
  console.log('in action');
  const { cors } = await authenticate.admin(request);
  return json({ ok: true, message: 'action' });
}
3 Likes