Authentication
Customers authenticate with email + one-time passcode (OTP) — no passwords needed. OAuth providers (Google, Facebook) are also supported.
OTP Login Flow
Two-step flow: enter email, then enter the 6-digit code.
<AuthOtpFlowProvider>
<AuthEmailStep>
<AuthOtpRequestProvider>
<AuthEmailField>
<TextFieldInput type="email" placeholder="Enter your email" />
</AuthEmailField>
<MutationError />
<MutationButton>Send Code</MutationButton>
</AuthOtpRequestProvider>
</AuthEmailStep>
<AuthVerifyStep>
<AuthOtpProvider>
<AuthOtpField>
<OTPFieldInput />
<OTPFieldGroup>
<OTPFieldSlot index={0} />
<OTPFieldSlot index={1} />
<OTPFieldSlot index={2} />
</OTPFieldGroup>
<OTPFieldSeparator />
<OTPFieldGroup>
<OTPFieldSlot index={3} />
<OTPFieldSlot index={4} />
<OTPFieldSlot index={5} />
</OTPFieldGroup>
</AuthOtpField>
<MutationError />
<MutationButton>Verify</MutationButton>
</AuthOtpProvider>
</AuthVerifyStep>
</AuthOtpFlowProvider>
AuthEmailStep shows when the user hasn't entered their email. AuthVerifyStep shows after the code is sent. Switching between steps is automatic.
Auto-Verify
Set autoVerify on AuthOtpField to skip the verify button — the mutation fires automatically when all slots are filled:
<AuthOtpProvider>
<AuthOtpField autoVerify>
<OTPFieldInput />
<OTPFieldGroup>
<OTPFieldSlot index={0} />
<OTPFieldSlot index={1} />
<OTPFieldSlot index={2} />
</OTPFieldGroup>
<OTPFieldSeparator />
<OTPFieldGroup>
<OTPFieldSlot index={3} />
<OTPFieldSlot index={4} />
<OTPFieldSlot index={5} />
</OTPFieldGroup>
</AuthOtpField>
</AuthOtpProvider>
OAuth Login
Provider buttons redirect to Google or Facebook, then back to your storefront:
<AuthGoogleButton />
<AuthFacebookButton />
Configure OAuth providers in Admin → Settings → Integrations. Handle the OAuth callback on your redirect page:
<OAuthCallbackHandler fallbackRedirect="/">
<p>Completing sign-in...</p>
</OAuthCallbackHandler>
Guest Checkout
Authentication is optional. Users can browse and add to cart without logging in. The OTP flow triggers at checkout if the user isn't authenticated — no login wall before purchase.
Auth State
useAuth() is available anywhere in the app. AuthProvider is auto-mounted in the root layout:
const { user, isAuthenticated, isLoading, logout } = useAuth()