Shopify Hydrogen App Authentication

Topic summary

A developer encountered an OAuth authentication error while building a Shopify Hydrogen app with local login functionality. The error occurred during redirect to the account page, triggered by Remix loaders.

Problem Details:

  • Error appeared on the OAuth authorization URL with localhost:3000 redirect
  • Issue involved the account route structure and authentication flow
  • Screenshots showed the error page and route file structure

Solution Provided:
Configure environment variables for the app URL, API key, and secret, then implement three key routes:

  1. Environment setup - Define PUBLIC_APP_URL, SHOPIFY_APP_API_KEY, and SHOPIFY_APP_SECRET
  2. auth._authorize.tsx - Initiates OAuth flow with proper redirect URI
  3. auth.callback.tsx - Handles the OAuth callback and token exchange
  4. Protect account routes - Add authentication checks in loaders before rendering

Resolution:
The developer confirmed the solution worked after implementing the suggested authentication flow structure.

Summarized with AI on October 28. AI used: claude-sonnet-4-5-20250929.

Hey I am creating a shopify hydrogen app and currently want ot login form my local app. Unfortunaelty it shows up the mentioned error in the image. Looks like it redirects me to my account page where the error is being trigerred by remix loaders.

Anyone has ever experienced integrating user auth flow in hydrogen app.

This is the link that the error page loads:
https://shopify.com/authentication/60802433076/oauth/authorize?client_id=shp_429055a5-1cf3-4e9f-ad61-12b3e500bb88&scope=openid+email+customer-account-api%3Afull&response_type=code&redirect_uri=https%3A%2F%2Flocalhost%3A3000%2Faccount%2Fauthorize&state=17461138725200jlntbybumyl&nonce=b425f3e8d060200f5a50ac090c0d3873&ui_locales=en&code_challenge=q9aWPaLCVppf9xXuqGqvSU22INLa9B5NizHQeScjPIk&code_challenge_method=S256

The following is my routes structure of account files:

Create an .env file if you haven’t already:

env

CopyEdit

PUBLIC_APP_URL=http://localhost:3000 SHOPIFY_APP_API_KEY=your_api_key_here SHOPIFY_APP_SECRET=your_secret_here

 

In your app code:

ts

CopyEdit

const REDIRECT_URI = ${process.env.PUBLIC_APP_URL}/auth/callback;

 

:small_blue_diamond: 2. Route: app/routes/auth._authorize.tsx

Use this route to initiate OAuth:

tsx

CopyEdit

// app/routes/auth._authorize.tsx import { LoaderFunction, redirect } from “@remix-run/node”; export const loader: LoaderFunction = async ({ request }) => { const shop = new URL(request.url).searchParams.get(“shop”); if (!shop) { return new Response(“Missing shop parameter”, { status: 400 }); } const redirectUri = ${process.env.PUBLIC_APP_URL}/auth/callback; const oauthUrl = https://${shop}/admin/oauth/authorize?client_id=${process.env.SHOPIFY_APP_API_KEY}&scope=read_products,write_orders&redirect_uri=${encodeURIComponent( redirectUri )}&state=noncevalue&grant_options[]=per-user; return redirect(oauthUrl); };

 

:small_blue_diamond: 3. Route: app/routes/auth.callback.tsx

This is where Shopify redirects after OAuth — here you handle the token exchange:

tsx

CopyEdit

// app/routes/auth.callback.tsx import { LoaderFunction, redirect } from “@remix-run/node”; export const loader: LoaderFunction = async ({ request }) => { const url = new URL(request.url); const shop = url.searchParams.get(“shop”); const code = url.searchParams.get(“code”); if (!shop || !code) { return new Response(“Invalid callback params”, { status: 400 }); } // Exchange code for token or do what your app needs here // Redirect to account or dashboard after successful auth return redirect(“/account”); };

 

:shield: Bonus: Protect account._index.tsx Loader

Make sure your account._index.tsx loader checks that the user is authenticated before rendering:

tsx

CopyEdit

// app/routes/account._index.tsx import { LoaderFunction, redirect } from “@remix-run/node”; export const loader: LoaderFunction = async ({ request }) => { // Example: Check for session/token const user = await getUserFromSession(request); if (!user) { return redirect(“/auth/authorize?shop=myshop.myshopify.com”); } return { user }; };

 

Where exactly I should put the following:

const REDIRECT_URI = ${process.env.PUBLIC_APP_URL}/auth/callback;

Thanks for the hint, it worked.