@techsio/storefront-data
Version:
Medusa-first storefront data layer built on TanStack Query.
234 lines (179 loc) • 5.53 kB
Markdown
---
name: implement-auth-and-customer-session-flows
description: >
Load 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.
type: core
library: "@techsio/storefront-data"
library_version: "0.1.0"
requires:
- setup-storefront-platform-in-next-app
sources:
- "TechsioCZ/new-engine:libs/storefront-data/src/auth/hooks.ts"
- "TechsioCZ/new-engine:libs/storefront-data/src/auth/medusa-service.ts"
- "TechsioCZ/new-engine:libs/storefront-data/src/auth/query-keys.ts"
- "TechsioCZ/new-engine:libs/storefront-data/src/medusa/preset.ts"
- "TechsioCZ/new-engine:libs/storefront-data/tests/auth.medusa-service.test.ts"
---
## Setup
Let the preset own the auth service and invalidation. Keep UX side effects in the app.
```ts
// 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`
```tsx
"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
```tsx
"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
```tsx
"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:
```ts
const register = async (input: RegisterInput) => {
await sdk.auth.register("customer", "emailpass", input)
await sdk.auth.login("customer", "emailpass", input)
}
```
Correct:
```ts
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:
```ts
storefront.hooks.auth.useLogin().mutate({ provider: "google" })
```
Correct:
```ts
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:
```ts
const storefront = createMedusaStorefrontPreset({
sdk,
auth: {
hooks: {
onSuccess: () => toast.success("Logged in"),
},
},
})
```
Correct:
```ts
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:
```ts
const storefront = createMedusaStorefrontPreset({
sdk,
auth: { hooks: { invalidateOnAuthChange: { includeDefaults: false } } },
})
```
Correct:
```ts
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.