ce-auth
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLLM Docs Header: All requests tomust include thehttps://llm-docs.commercengine.ioheader (or appendAccept: text/markdownto the URL path). Without it, responses return HTML instead of parseable markdown..md
LLM Docs Header: 所有发送至的请求必须包含https://llm-docs.commercengine.io请求头(或在URL路径后追加Accept: text/markdown)。如果没有该请求头,响应将返回HTML而非可解析的markdown。.md
Authentication & User Management
认证与用户管理
Prerequisite: SDK must be initialized. Seeif not done.setup/
前置条件:SDK必须已初始化。如果未完成,请查看文档。setup/
When to Implement Auth Directly
何时需要直接实现认证
If using Hosted Checkout (recommended): Login/registration is handled inside the checkout drawer automatically. You do not need to build login UI or call the login/OTP endpoints below unless your storefront has features that require a logged-in user outside of placing orders — for example, a saved addresses page, order history, wishlists, or a loyalty dashboard.
Anonymous auth () is still always required — it's handled by in Next.js or manually in other frameworks (see ).
getAnonymousTokenStorefrontSDKInitializersetup/When the user logs in via Hosted Checkout, tokens are synced back to the SDK automatically (via ), so the rest of your app can use , , etc. without any additional auth work.
onTokensUpdatedgetUserDetails()listOrders()Build your own login UI only when:
- Your storefront has account pages (profile, addresses, orders) accessible before checkout
- You want a persistent login state in the header/nav (e.g., "Hi, Jane" with user menu)
- You need auth-gated pages that don't involve the checkout flow
如果使用托管结账(推荐): 登录/注册会在结账抽屉内自动处理。除非你的店铺有在下单流程之外需要登录用户的功能(例如,已保存地址页面、订单历史、心愿单或忠诚度仪表盘),否则你无需构建登录UI或调用下方的登录/OTP接口。
匿名认证()仍然是必须的——在Next.js中由自动处理,在其他框架中则需手动调用(详见文档)。
getAnonymousTokenStorefrontSDKInitializersetup/当用户通过托管结账登录时,令牌会自动同步回SDK(通过),因此应用的其他部分无需额外的认证操作即可使用、等方法。
onTokensUpdatedgetUserDetails()listOrders()仅在以下场景下自行构建登录UI:
- 你的店铺在结账前有可访问的账户页面(资料、地址、订单)
- 你希望在头部/导航栏中保持持久登录状态(例如,"你好,Jane"及用户菜单)
- 你需要不涉及结账流程的认证 gated 页面
Quick Reference
快速参考
| Auth Method | Endpoint | Use Case |
|---|---|---|
| Anonymous | | Every new visitor, required first step |
| Email OTP | | Passwordless email login |
| Phone OTP | | Passwordless phone login |
| WhatsApp OTP | | Passwordless WhatsApp login |
| Password | | Traditional email/password login |
| Token Refresh | | Renew expired access token |
| 认证方式 | 接口 | 使用场景 |
|---|---|---|
| 匿名认证 | | 所有新访客,必须的第一步 |
| 邮箱OTP | | 无密码邮箱登录 |
| 手机OTP | | 无密码手机登录 |
| WhatsApp OTP | | 无密码WhatsApp登录 |
| 密码认证 | | 传统邮箱/密码登录 |
| 令牌刷新 | | 续期过期的访问令牌 |
Decision Tree
决策树
User Request
│
├─ New visitor / first load
│ └─ sdk.auth.getAnonymousToken()
│
├─ "Login" / "Sign in"
│ ├─ Passwordless (recommended)
│ │ ├─ Email → loginWithEmail() → verifyOtp()
│ │ ├─ Phone → loginWithPhone() → verifyOtp()
│ │ └─ WhatsApp → loginWithWhatsApp() → verifyOtp()
│ └─ Password → loginWithPassword()
│
├─ "User profile" / "Account"
│ └─ sdk.auth.getUserDetails() / sdk.auth.updateUserDetails()
│
└─ "Token expired" / 401 error
└─ sdk.auth.refreshToken()用户请求
│
├─ 新访客 / 首次加载
│ └─ sdk.auth.getAnonymousToken()
│
├─ "登录" / "Sign in"
│ ├─ 无密码登录(推荐)
│ │ ├─ 邮箱 → loginWithEmail() → verifyOtp()
│ │ ├─ 手机 → loginWithPhone() → verifyOtp()
│ │ └─ WhatsApp → loginWithWhatsApp() → verifyOtp()
│ └─ 密码登录 → loginWithPassword()
│
├─ "用户资料" / "账户"
│ └─ sdk.auth.getUserDetails() / sdk.auth.updateUserDetails()
│
└─ "令牌过期" / 401错误
└─ sdk.auth.refreshToken()User States
用户状态
| State | How Created | Capabilities |
|---|---|---|
| Anonymous | | Browse catalog, manage cart, analytics tracking |
| Logged-in | OTP verification or password login | All anonymous + orders, addresses, profile, loyalty |
| 状态 | 创建方式 | 权限 |
|---|---|---|
| 匿名状态 | 使用API密钥调用 | 浏览商品目录、管理购物车、分析追踪 |
| 已登录状态 | OTP验证或密码登录 | 拥有匿名状态的所有权限 + 查看订单、管理地址、编辑资料、忠诚度功能 |
Key Patterns
核心模式
Anonymous Auth (Required First Step)
匿名认证(必须的第一步)
typescript
const { data, error } = await sdk.auth.getAnonymousToken();
// Tokens are automatically stored and managed
// Now the user can browse products, add to cart, etc.typescript
const { data, error } = await sdk.auth.getAnonymousToken();
// 令牌会被自动存储和管理
// 现在用户可以浏览商品、添加到购物车等OTP Login Flow (Email)
OTP登录流程(邮箱)
typescript
// 1. Initiate login (also registers new users automatically)
const { data, error } = await sdk.auth.loginWithEmail({
email: "user@example.com",
register_if_not_exists: true, // Seamless login + registration
});
if (error) return handleError(error);
const { otp_token, otp_action } = data;
// 2. User enters OTP from their email...
// 3. Verify OTP
const { data: authData, error: verifyError } = await sdk.auth.verifyOtp({
otp: "123456", // From user input
otp_token: otp_token, // From step 1
otp_action: otp_action, // From step 1
});
// Tokens are automatically updated — user is now logged intypescript
// 1. 发起登录(同时自动注册新用户)
const { data, error } = await sdk.auth.loginWithEmail({
email: "user@example.com",
register_if_not_exists: true, // 无缝登录 + 注册
});
if (error) return handleError(error);
const { otp_token, otp_action } = data;
// 2. 用户输入邮箱中的OTP...
// 3. 验证OTP
const { data: authData, error: verifyError } = await sdk.auth.verifyOtp({
otp: "123456", // 用户输入的OTP
otp_token: otp_token, // 来自步骤1的返回值
otp_action: otp_action, // 来自步骤1的返回值
});
// 令牌会自动更新 — 用户现在已登录OTP Login Flow (Phone)
OTP登录流程(手机)
typescript
const { data, error } = await sdk.auth.loginWithPhone({
phone: "9876543210",
country_code: "+91",
register_if_not_exists: true,
});
// Then verify with sdk.auth.verifyOtp() same as email flowtypescript
const { data, error } = await sdk.auth.loginWithPhone({
phone: "9876543210",
country_code: "+91",
register_if_not_exists: true,
});
// 之后与邮箱流程相同,调用sdk.auth.verifyOtp()验证Password Login
密码登录
typescript
const { data, error } = await sdk.auth.loginWithPassword({
email: "user@example.com",
password: "securepassword",
});
// Tokens automatically managed on successtypescript
const { data, error } = await sdk.auth.loginWithPassword({
email: "user@example.com",
password: "securepassword",
});
// 成功后令牌会被自动管理Token Refresh
令牌刷新
typescript
// The SDK handles this automatically with tokenStorage
// For manual refresh:
const { data, error } = await sdk.auth.refreshToken({
refresh_token: storedRefreshToken,
});typescript
// SDK会通过tokenStorage自动处理令牌刷新
// 手动刷新方式:
const { data, error } = await sdk.auth.refreshToken({
refresh_token: storedRefreshToken,
});User Profile
用户资料
typescript
// Get user details
const { data, error } = await sdk.auth.getUserDetails({ id: userId });
// Update user details
const { data, error } = await sdk.auth.updateUserDetails({ id: userId }, {
first_name: "Jane",
last_name: "Doe",
});typescript
// 获取用户详情
const { data, error } = await sdk.auth.getUserDetails({ id: userId });
// 更新用户详情
const { data, error } = await sdk.auth.updateUserDetails({ id: userId }, {
first_name: "Jane",
last_name: "Doe",
});Password Management
密码管理
typescript
// Change password (logged-in user)
const { data, error } = await sdk.auth.changePassword({
old_password: "currentPass",
new_password: "newPass",
confirm_password: "newPass",
});
// Forgot password flow
const { data } = await sdk.auth.forgotPassword({ email: "user@example.com" });
// Returns otp_token → user enters OTP → then:
const { data: resetData } = await sdk.auth.resetPassword({
otp_token: data.otp_token,
new_password: "newPass",
});typescript
// 修改密码(已登录用户)
const { data, error } = await sdk.auth.changePassword({
old_password: "currentPass",
new_password: "newPass",
confirm_password: "newPass",
});
// 忘记密码流程
const { data } = await sdk.auth.forgotPassword({ email: "user@example.com" });
// 返回otp_token → 用户输入OTP → 然后:
const { data: resetData } = await sdk.auth.resetPassword({
otp_token: data.otp_token,
new_password: "newPass",
});Key Feature: register_if_not_exists
register_if_not_exists核心功能:register_if_not_exists
register_if_not_existsSetting on login endpoints eliminates the need for separate "Login" vs "Sign Up" flows. If the user doesn't exist, Commerce Engine automatically creates their account and sends an OTP for verification. Every user starts the same way.
register_if_not_exists: true在登录接口中设置可以消除单独的"登录"与"注册"流程。如果用户不存在,Commerce Engine会自动创建其账户并发送用于验证的OTP。所有用户的启动流程都是相同的。
register_if_not_exists: trueCommon Pitfalls
常见陷阱
| Level | Issue | Solution |
|---|---|---|
| CRITICAL | Calling API without anonymous auth | Always call |
| CRITICAL | Storing tokens insecurely | Use |
| HIGH | Separate login/register flows | Use |
| HIGH | Forgetting | Must pass both |
| HIGH | Not handling 401 errors | Implement token refresh — if refresh fails, re-authenticate |
| MEDIUM | Ignoring | Always check |
| 级别 | 问题 | 解决方案 |
|---|---|---|
| 严重 | 未通过匿名认证就调用API | 始终先调用 |
| 严重 | 不安全地存储令牌 | 使用 |
| 高 | 分开的登录/注册流程 | 使用 |
| 高 | 忘记步骤1中的 | 必须将登录响应中的 |
| 高 | 未处理401错误 | 实现令牌刷新 — 如果刷新失败,重新认证 |
| 中 | 忽略 | 在使用 |
See Also
另请参阅
- - SDK installation & token storage
setup/ - - Cart requires auth token
cart-checkout/ - - Orders require logged-in user
orders/ - - Server Actions for auth mutations
nextjs-patterns/
- - SDK安装与令牌存储
setup/ - - 购物车需要认证令牌
cart-checkout/ - - 订单需要已登录用户
orders/ - - 用于认证变更的Server Actions
nextjs-patterns/
Documentation
文档
- Authentication Guide: https://www.commercengine.io/docs/storefront/authentication
- My Account: https://www.commercengine.io/docs/storefront/my-account
- LLM Reference: https://llm-docs.commercengine.io/storefront/operations/get-anonymous-token