Checkout Redirect Issue After Custom Login on Hydrogen Dev Site

Hey all,

I’m running into an issue with my custom login implementation on our Hydrogen dev site. We’ve built a custom login flow (using our legacy code as reference) that creates a customer access token and updates the cart’s buyer identity. The login flow works fine on the dev site – after logging in, the user’s session is updated, and the cart is either synced (via cart.updateBuyerIdentity()) or created with the correct buyer identity.

A minimized version of our login code looks like this:

import { useState } from 'react';
import { json, redirect } from '@shopify/remix-oxygen';
import { Form, useActionData } from '@remix-run/react';

export const handle = { isPublic: true };

export async function action({ request, context }) {
  const { storefront, session, cart } = context;
  const formData = await request.formData();
  const email = formData.get('email');
  const password = formData.get('password');

  if (!email || !password) {
    return json({ error: 'Email and password required.' }, { status: 400 });
  }

  try {
    // Get customer access token
    const data = await storefront.mutate(CUSTOMER_ACCESS_TOKEN_CREATE_MUTATION, {
      variables: { input: { email, password } },
    });

    // Handle errors and extract token
    const { customerAccessToken } = data.customerAccessTokenCreate;
    if (!customerAccessToken?.accessToken) {
      return json({ error: 'Login failed.' }, { status: 500 });
    }
    
    session.set('customerAccessToken', customerAccessToken.accessToken);
    if (customerAccessToken.expiresAt) {
      session.set('customerAccessTokenExpiresAt', customerAccessToken.expiresAt);
    }

    let headers = new Headers();

    // Check for an existing cart and update buyer identity
    try {
      const currentCart = await cart.get();
      console.log("Checkout URL:", currentCart.checkoutUrl);
      if (currentCart?.id) {
        const result = await cart.updateBuyerIdentity({
          customerAccessToken: customerAccessToken.accessToken,
        });
        if (result?.cart?.id) {
          headers = cart.setCartId(result.cart.id);
        }
      } else {
        // Create a new cart with buyer identity if none exists
        const result = await storefront.mutate(CART_CREATE_MUTATION, {
          variables: { input: { buyerIdentity: { customerAccessToken: customerAccessToken.accessToken } } },
        });
        if (result?.cartCreate?.cart?.id) {
          headers = cart.setCartId(result.cartCreate.cart.id);
        }
      }
    } catch (cartError) {
      console.error('Cart error:', cartError);
    }

    headers.append('Set-Cookie', await session.commit());
    return redirect('/', { headers });
  } catch (error) {
    console.error('Login error:', error);
    return json({ error: 'Unexpected error occurred.' }, { status: 500 });
  }
}

export default function Login() {
  const actionData = useActionData();
  const [isSubmitting, setIsSubmitting] = useState(false);
  
  return (
    <Form method="post" onSubmit={() => setIsSubmitting(true)}>
      {/* Minimal form fields for email and password */}
      <input name="email" type="email" required />
      <input name="password" type="password" required />
      <button type="submit" disabled={isSubmitting}>Sign in</button>
      {actionData?.error && <p>{actionData.error}</p>}
    </Form>
  );
}

On our Hydrogen dev site (launched via npx shopify hydrogen dev --customer-account-push__unstable), the login works and we see debug info confirming the user is logged in and the cart is updated. However, when I click the “Checkout” link in our cart summary component, it doesn’t recognize the login on the Hydrogen site. Instead, it redirects to our live production login (or checkout) page. For users who are logged into the production store, everything seems fine.

Here’s our (also minimized) cart summary snippet where we pass the checkout URL:

function CartCheckoutActions({ checkoutUrl }) {
  const data = useRouteLoaderData('root');
  let finalCheckoutUrl = checkoutUrl;
  if (data?.isLoggedIn && data?.customerAccessToken) {
    finalCheckoutUrl = `${checkoutUrl}`; // keeping it the same for now
  }
  return (
    <a href={finalCheckoutUrl} target="_self">
      Checkout &rarr;
    </a>
  );
}

My Questions:

  1. Is this behavior expected on a Hydrogen dev site?
    Is it normal for the checkoutUrl (which is Shopify-hosted) to point to our production site login when accessed from the dev environment?
  2. Will this be resolved upon migrating fully to Hydrogen, or is there a misconfiguration in how I’m updating the buyer identity?
    I noticed that the checkoutUrl is generated by Shopify based on our storefront settings, so perhaps it’s still referencing the legacy domain?

I’d love any insights, suggestions, or recommendations on how to ensure the checkout on our Hydrogen dev site properly recognizes the logged-in state. Thanks in advance!

Yes, because checkout is hosted by Shopify, there is a single checkout experience that is shared during dev and prod.

Will this be resolved upon migrating fully to Hydrogen

I assume so, but hard to know without looking at your code. I just tried running our skeleton template locally, and logging in persists to checkout.