@techsio/storefront-data
implement-auth-and-customer-session-flows
coreLoad this skill when using @techsio/storefront-data for customer auth and session state through storefront.hooks.auth.useAuth, useLogin, useRegister, useLogout, and invalidateOnAuthChange. Use it for login/register flows, session-aware rendering, cross-domain invalidation, and app-level callbacks for toasts, analytics, or redirects.
Setup
Let the preset own the auth service and invalidation. Keep UX side effects in the app.
// src/lib/storefront.ts
import { createMedusaSdk } from "@techsio/storefront-data/shared/medusa-client"
import { createMedusaStorefrontPreset } from "@techsio/storefront-data/medusa/preset"
const sdk = createMedusaSdk({
baseUrl: process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL ?? "http://localhost:9000",
publishableKey: process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY ?? "",
})
export const storefront = createMedusaStorefrontPreset({
sdk,
queryKeyNamespace: "shop",
auth: {
hooks: {
invalidateOnAuthChange: {
includeDefaults: true,
},
},
},
})Core Patterns
Gate account UI through useAuth
"use client"
import { storefront } from "@/src/lib/storefront"
export function AccountGate() {
const auth = storefront.hooks.auth.useAuth()
if (auth.isLoading) return <div>Loading...</div>
if (!auth.isAuthenticated) return <div>Please sign in</div>
return <div>{auth.customer?.email}</div>
}Keep UX side effects in app callbacks
"use client"
import { storefront } from "@/src/lib/storefront"
import { toast } from "sonner"
const track = (event: string) => {
console.log(event)
}
export function LoginButton() {
const login = storefront.hooks.auth.useLogin({
onSuccess: () => {
toast.success("Logged in")
},
})
return (
<button
type="button"
onClick={() => login.mutate({ email: "alice@example.com", password: "secret" })}
>
Log in
</button>
)
}Recover registration edge cases through the shared register hook
"use client"
import { storefront } from "@/src/lib/storefront"
export function RegisterButton() {
const register = storefront.hooks.auth.useRegister()
return (
<button
type="button"
onClick={() =>
register.mutate({
email: "alice@example.com",
password: "secret",
first_name: "Alice",
last_name: "Example",
})
}
>
Register
</button>
)
}The shared auth service already handles the Medusa-specific recovery and cleanup semantics. The app should only add storefront policy around it.
Common Mistakes
HIGH Rebuilding auth in the app
Wrong:
const register = async (input: RegisterInput) => {
await sdk.auth.register("customer", "emailpass", input)
await sdk.auth.login("customer", "emailpass", input)
}Correct:
const register = storefront.hooks.auth.useRegister()
register.mutate(input)Local auth re-implementation reintroduces the exact cleanup and invalidation bugs that the shared auth surface is meant to absorb.
Source: libs/storefront-data/src/auth/medusa-service.ts, libs/storefront-data/src/auth/hooks.ts
CRITICAL Assuming multi-step auth is already supported
Wrong:
storefront.hooks.auth.useLogin().mutate({ provider: "google" })Correct:
storefront.hooks.auth.useLogin().mutate({
email: "alice@example.com",
password: "secret",
})The current Medusa auth adapter rejects multi-step flows. The obvious generic-provider shape is misleading here.
Source: libs/storefront-data/src/auth/medusa-service.ts, libs/storefront-data/tests/auth.medusa-service.test.ts
HIGH Putting UX callbacks into shared auth code
Wrong:
const storefront = createMedusaStorefrontPreset({
sdk,
auth: {
hooks: {
onSuccess: () => toast.success("Logged in"),
},
},
})Correct:
const login = storefront.hooks.auth.useLogin({
onSuccess: () => {
toast.success("Logged in")
track("login_success")
},
})Toasts, redirects, analytics, and debug behavior belong in the app layer, not inside the shared auth contract.
Source: libs/storefront-data/src/auth/hooks.ts, maintainer interview
HIGH Forgetting cross-domain invalidation needs
Wrong:
const storefront = createMedusaStorefrontPreset({
sdk,
auth: { hooks: { invalidateOnAuthChange: { includeDefaults: false } } },
})Correct:
const storefront = createMedusaStorefrontPreset({
sdk,
auth: {
hooks: {
invalidateOnAuthChange: {
includeDefaults: true,
},
},
},
})Auth changes usually affect customer and order data. If you turn off default invalidation, do it intentionally and replace it with equivalent app-specific rules.
Source: libs/storefront-data/src/medusa/preset.ts, libs/storefront-data/src/auth/hooks.ts
See also: decide-app-specific-overrides-vs-shared-platform for thin wrapper rules.