| name | auth-web-cloudbase |
| description | Complete guide for CloudBase Auth v2 using Web SDK (@cloudbase/js-sdk@2.x) - all login flows, user management, captcha handling, and best practices in one file. |
| alwaysApply | false |
When to use this skill
Use this skill for frontend Web authentication in a CloudBase project, using the new auth system (Auth v2) and @cloudbase/js-sdk@2.x.
Use it when you need to:
- Design and implement login/sign-up flows in a browser app
- Integrate CloudBase identity (
uid, tokens) with your own backend - Manage sessions and user profiles on the frontend
Default login method: If not specified, assume phone number + SMS verification code (passwordless).
Do NOT use for:
- Server-side auth (Node SDK)
- Direct HTTP API calls (use the CloudBase HTTP Auth skill at
skills/auth-http-api-skill) - Database or storage operations (use database/storage skills)
How to use this skill (for a coding agent)
Confirm CloudBase environment
Ask the user for:
env– CloudBase environment ID
Always initialize the SDK in this pattern (update values only):
import cloudbase from "@cloudbase/js-sdk"; const app = cloudbase.init({ env: "xxxx-yyy", }); const auth = app.auth();CloudBase Web JS SDK must be initialized synchronously:
- Always use top-level
import cloudbase from "@cloudbase/js-sdk"; - Do not use dynamic imports like
import("@cloudbase/js-sdk")or async wrappers such asinitCloudBase()with internalinitPromise
- Always use top-level
Check console configuration (do not assume it's done)
- ⚠️ MANDATORY: Always guide users to configure login methods in console
- Console URL format:
https://tcb.cloud.tencent.com/dev?envId={envId}#/identity/login-manage- Replace
{envId}with the actual CloudBase environment ID (e.g.,zirali-7gwqot6f31a0ab27) - Example:
https://tcb.cloud.tencent.com/dev?envId=test-xxx#/identity/login-manage
- Replace
- Before implementing any login flow, you MUST:
- Guide the user to open the console login management page using the URL above
- Confirm the required 登录方式 are enabled(短信 / 邮箱 / 用户名密码 / 微信开放平台 / 自定义登录)
- Confirm 短信/邮箱 模板已配置(if using SMS/email login)
- Confirm 当前 Web 域名已加入 安全域名 (安全来源列表)
- If something is missing, explain clearly what the user must configure and provide the console URL.
Pick a scenario from this file
- For login / sign-up, start with Scenario 1–8.
- For session & user info, use Scenario 9–22.
- Never invent new auth flows; always adapt from an existing scenario.
Follow CloudBase API shapes exactly
- Treat method names and parameter shapes in this file as canonical.
- You may change variable names and UI, but do not change API names or field names.
If you’re unsure about an API
- If an API is not documented there, do not use or invent it. Instead:
- Use a documented Web SDK API, or
- Ask the user to use a Node/HTTP skill for server-side or HTTP flows.
- If an API is not documented there, do not use or invent it. Instead:
Installation and initialization
npm install --save @cloudbase/js-sdk
import cloudbase from "@cloudbase/js-sdk";
const app = cloudbase.init({
env: "your-env-id", // CloudBase 环境 ID
});
const auth = app.auth();
Initialization rules (Web, @cloudbase/js-sdk):
- Always use synchronous initialization with the pattern above
- Do not lazy-load the SDK with
import("@cloudbase/js-sdk") - Do not wrap SDK initialization in async helpers such as
initCloudBase()with internalinitPromisecaches - Keep a single shared
app/authinstance in your frontend app; reuse it instead of re-initializing
⚠️ Important: Console Configuration Required
Before using any login method, you MUST configure it in the CloudBase console:
Open login management page:
- Console URL:
https://tcb.cloud.tencent.com/dev?envId={envId}#/identity/login-manage - Replace
{envId}with your actual CloudBase environment ID - Example:
https://tcb.cloud.tencent.com/dev?envId=zirali-7gwqot6f31a0ab27#/identity/login-manage
- Console URL:
Enable required login methods:
- 匿名登录 (Anonymous login)
- 短信验证码登录 (SMS verification code login)
- 邮箱验证码登录 (Email verification code login)
- 用户名密码登录 (Username/password login)
- 微信开放平台登录 (WeChat Open Platform login)
- 自定义登录 (Custom login)
Configure SMS/Email templates (if using SMS/email login):
- Set up verification code templates in console
Add Web domain to 安全来源列表 (Security Domain Whitelist):
- Go to: 云开发控制台 → 身份认证 → 登录方式 → 安全域名
- Add your frontend domain (e.g.,
https://your-app.com,http://localhost:3000)
⚠️ If login methods are not enabled or domain is not whitelisted, authentication will fail.
Core concepts
User types:
- Internal users (phone/email/username)
- External users (WeChat, etc.)
- Anonymous users (temporary, stable
uid)
Tokens:
access_token(JWT, 2 hours) – for API callsrefresh_token(30 days) – auto-refreshed by SDK- Login state persisted in localStorage for 30 days
All login scenarios (flat list)
Scenario 1: SMS login (passwordless, recommended default)
// Collect user's phone number into variable `phoneNum` by providing a input UI
// Send SMS code
const verificationInfo = await auth.getVerification({
phone_number: `+86 ${phoneNum}`,
});
// Collect user's phone number into variable `verificationCode` by providing a input UI
// Sign in
await auth.signInWithSms({
verificationInfo,
verificationCode,
phoneNum,
});
// Logged in
const user = await auth.getCurrentUser();
Scenario 2: Email login (passwordless)
const email = "test@example.com";
const verificationInfo = await auth.getVerification({ email });
const verificationCode = "000000";
await auth.signInWithEmail({
verificationInfo,
verificationCode,
email,
});
Scenario 3: Username/password login
await auth.signIn({
username: "your username", // phone, email, or username
password: "your password",
});
Scenario 4: Anonymous login
await auth.signInAnonymously();
const loginScope = await auth.loginScope();
console.log(loginScope === "anonymous"); // true
Scenario 5: Register new user (phone or email)
const phoneNumber = "+86 13800000000";
// Send verification code
const verification = await auth.getVerification({ phone_number: phoneNumber });
// Verify code
const verificationCode = "000000";
const verificationTokenRes = await auth.verify({
verification_id: verification.verification_id,
verification_code: verificationCode,
});
// Check if user exists
if (verification.is_user) {
// Existing user: sign in
await auth.signIn({
username: phoneNumber,
verification_token: verificationTokenRes.verification_token,
});
} else {
// New user: sign up (also logs in)
await auth.signUp({
phone_number: phoneNumber,
verification_code: verificationCode,
verification_token: verificationTokenRes.verification_token,
name: "手机用户", // optional
password: "password", // optional
username: "username", // optional
});
}
Scenario 6: WeChat OAuth login (3 steps)
// Step 1: Generate WeChat redirect URI
const { uri } = await auth.genProviderRedirectUri({
provider_id: "wx_open",
provider_redirect_uri: "https://your-app.com/callback",
state: "random_state",
});
window.location.href = uri;
// Step 2: In callback handler, get provider token
const urlParams = new URLSearchParams(window.location.search);
const provider_code = urlParams.get('code');
const { provider_token } = await auth.grantProviderToken({
provider_id: "wx_open",
provider_redirect_uri: window.location.href,
provider_code,
});
// Step 3: Sign in with provider token
await auth.signInWithProvider({ provider_token });
Scenario 7: Custom login (your own identity system, signInWithCustomTicket)
CloudBase flow(前后端配合)
- 后端(Node SDK)在验证完你自己用户系统后,使用
app.auth().createTicket()生成自定义登录 ticket。 - 前端通过
auth.setCustomSignFunc(getTicketFn)告诉 Web SDK 如何异步获取 ticket。 - 前端调用
auth.signInWithCustomTicket()完成登录。
// Backend (Node.js) 示例
// const cloudbase = require("@cloudbase/node-sdk");
// const app = cloudbase.init({ env: "your-env-id" });
// const ticket = await app.auth().createTicket("your-user-id", { refresh: 3600 * 1000 });
// res.json({ ticket });
// Frontend 示例
import cloudbase from "@cloudbase/js-sdk";
const app = cloudbase.init({
env: "your-env-id",
});
const auth = app.auth();
// 定义获取自定义 ticket 的函数(从你的后端获取)
const getTicketFn = async () => {
const res = await fetch("/api/get-custom-ticket");
const data = await res.json();
return data.ticket; // 后端返回的 ticket 字符串
};
// 告诉 Web SDK 如何获取自定义登录 ticket
await auth.setCustomSignFunc(getTicketFn);
// 使用自定义 ticket 登录
await auth.signInWithCustomTicket();
Scenario 8: Upgrade anonymous user to registered
// Already logged in anonymously
await auth.signInAnonymously();
// Get anonymous token
const { accessToken } = await auth.getAccessToken();
// Register with phone/email
const phoneNumber = "+86 13800000000";
const verification = await auth.getVerification({ phone_number: phoneNumber });
const verificationCode = "000000";
const verificationTokenRes = await auth.verify({
verification_id: verification.verification_id,
verification_code: verificationCode,
});
// Sign up with anonymous_token to link accounts
await auth.signUp({
phone_number: phoneNumber,
verification_code: verificationCode,
verification_token: verificationTokenRes.verification_token,
anonymous_token: accessToken, // Links to anonymous account
});
Scenario 9: Sign out
await auth.signOut();
Scenario 10: Get current user
const user = await auth.getCurrentUser();
if (user) {
console.log(user.uid, user.name, user.email, user.phone);
}
Scenario 11: Update user profile (User.update)
const user = await auth.getCurrentUser();
if (!user) {
throw new Error("No current user. Please sign in before updating profile.");
}
await user.update({
name: "New Name",
gender: "FEMALE", // 仅限于 "MALE" | "FEMALE" | "UNKNOWN"
picture: "https://example.com/avatar.jpg",
});
Scenario 12: Update password while logged in (Auth.sudo + Auth.setPassword)
CloudBase flow
- 用户已登录(可以通过
await auth.getCurrentUser()获取到用户)。 - 通过
auth.sudo(...)获取sudo_token:- 可以通过当前密码,或短信/邮箱验证码。
- 调用
auth.setPassword({ new_password, sudo_token })更新密码。
// 1. 用户输入当前密码
const oldPassword = "user_current_password";
// 2. 获取 sudo_token
const sudoRes = await auth.sudo({
password: oldPassword,
});
const sudoToken = sudoRes.sudo_token;
// 3. 设置新密码
await auth.setPassword({
new_password: "new_password",
sudo_token: sudoToken,
});
Scenario 13: Reset password (forgot password)
// Send verification code
const verification = await auth.getVerification({ email: "user@example.com" });
// Verify code
const verificationCode = "000000";
const verificationTokenRes = await auth.verify({
verification_id: verification.verification_id,
verification_code: verificationCode,
});
// Reset password
await auth.resetPassword({
email: "user@example.com",
new_password: "new_password",
verification_token: verificationTokenRes.verification_token,
});
Scenario 14: Link WeChat to existing account (Auth.bindWithProvider)
CloudBase flow
- 用户已登录(可以通过
await auth.getCurrentUser()获取到用户)。 - 通过
auth.genProviderRedirectUri获取微信授权地址并跳转。 - 在回调页使用
auth.grantProviderToken获取provider_token。 - 调用
auth.bindWithProvider({ provider_token })将微信账号绑定到当前 CloudBase 账号。
// 1. 在账号设置页点击“绑定微信”
// 生成微信授权地址
const { uri } = await auth.genProviderRedirectUri({
provider_id: "wx_open",
provider_redirect_uri: "https://your-app.com/bind-callback",
state: "bind_wechat",
});
// 跳转到微信授权
window.location.href = uri;
在回调页:
// 2. 微信回调页面
const urlParams = new URLSearchParams(window.location.search);
const provider_code = urlParams.get("code");
// 用 code 换取 provider_token
const { provider_token } = await auth.grantProviderToken({
provider_id: "wx_open",
provider_redirect_uri: window.location.href,
provider_code,
});
// 3. 绑定微信到当前账号
await auth.bindWithProvider({
provider_token,
});
Scenario 15: List and unbind third-party providers
CloudBase flow
- 使用
auth.getProviders()获取当前用户已绑定的三方列表。 - 使用
auth.unbindProvider({ provider_id })解除绑定。
// 获取绑定的三方账号列表
const providers = await auth.getProviders();
// providers: { id: string; name?: string; picture?: string; }[]
// 示例:解绑第一个 provider
if (providers.length > 0) {
const first = providers[0];
await auth.unbindProvider({
provider_id: first.id,
});
}
注:手机号/邮箱 绑定/解绑目前通过 HTTP 接口完成,本 Web SDK skill 不直接提供代码,请使用 HTTP Auth skill 或后端 Node SDK 来实现。
Scenario 16: Delete current account (Auth.sudo + Auth.deleteMe)
CloudBase flow
- 用户已登录。
- 通过
auth.sudo(...)获取sudo_token(用密码或验证码)。 - 使用
auth.deleteMe({ sudo_token })删除当前账号。
// 1. 让用户输入当前密码确认删除
const password = "user_current_password";
// 2. 获取 sudo_token
const sudoRes = await auth.sudo({ password });
const sudoToken = sudoRes.sudo_token;
// 3. 删除当前账号
await auth.deleteMe({
sudo_token: sudoToken,
});
// 当前会话结束,用户已被删除
Scenario 17: Listen for login state changes (Auth.onLoginStateChanged)
CloudBase flow
- 使用
app.auth().onLoginStateChanged(callback)监听登录状态变化。 - 回调
params.data.eventType可能为:sign_in/sign_out/refresh_token_failed等。 - 注意:
onLoginStateChanged返回值为undefined,不会返回取消订阅函数或 Promise;不要把返回值当作清理句柄或去await它,只需要注册一次监听即可。
app.auth().onLoginStateChanged((params) => {
console.log(params);
const { eventType } = params?.data || {};
switch (eventType) {
case "sign_in":
// 登录成功
break;
case "sign_out":
// 退出登录
break;
case "refresh_token_failed":
// 刷新 token 失败,需要提示用户重新登录
break;
default:
break;
}
});
Scenario 18: Get access token for backend verification
const { accessToken, accessTokenExpire } = await auth.getAccessToken();
// 将 accessToken 通过 Authorization 头传给自有后端
await fetch("/api/protected", {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
Scenario 19: Refresh user data from server
const user = await auth.getCurrentUser();
if (user) {
await user.refresh();
// user 对象现在包含最新的用户信息
console.log(user.name, user.picture);
}
Captcha handling
When captcha is triggered
CloudBase 在出现异常频率或风控触发时,会对 发送验证码 / 登录 等操作返回 CAPTCHA_REQUIRED 错误码。
Web SDK 本身不会直接提供 getCaptcha / verifyCaptcha 方法,验证码图片/校验通常通过 HTTP 接口 完成(例如:获取图片验证码.api.mdx、验证图片验证码.api.mdx)。
在前端代码中,你应当:
- 捕获
CAPTCHA_REQUIRED错误。 - 提示用户需要完成图形验证码。
- 通过 HTTP Auth skill 或后端服务调用图形验证码相关接口,并在后续的
getVerification/ 登录请求中附带后端返回的captcha_token等信息。
示例(仅展示 error flow,不展示 HTTP 细节):
try {
await auth.getVerification({ phone_number: "+86 13800000000" });
} catch (error) {
if (error.code === "CAPTCHA_REQUIRED") {
// 提示用户需要完成图形验证码
// 具体实现:调用 HTTP 接口获取验证码图片并校验,参考 HTTP Auth skill
console.log("需要图形验证码,请调用 HTTP 验证码接口");
}
}
Rate limits(参考控制台配置)
- 验证码发送频率:对同一手机号/邮箱、同一 IP 有频率限制。
- 登录失败次数:连续密码错误会触发风控,需要稍后重试或走验证码流程。
Error handling
Common error codes
try {
await auth.signIn({ username: "user", password: "wrong" });
} catch (error) {
console.error(error.code, error.message);
// 常见错误码:
// INVALID_CREDENTIALS - 用户名或密码错误
// VERIFICATION_CODE_EXPIRED - 验证码过期
// VERIFICATION_CODE_INVALID - 验证码错误
// RATE_LIMIT_EXCEEDED - 触发频率限制
// CAPTCHA_REQUIRED - 需要图形验证码
// USER_NOT_FOUND - 用户不存在
// USER_ALREADY_EXISTS - 用户已存在
}
Best practices
Security
- Always validate on server - 前端只负责 UX,鉴权应在后端基于
access_token完成。 - Use HTTPS only - 生产环境必须使用 HTTPS(除 localhost 外)。
- Whitelist domains - 将所有前端域名加入 控制台「安全域名」。
- Re-auth for sensitive ops - 删除账号等操作前先调用
auth.sudo重新校验身份。
UX
- Check existing login - 页面初始化时通过
await auth.getCurrentUser()检查当前登录状态,避免重复登录。 - Handle session expiry - 使用
onLoginStateChanged监听 token 失效,提示用户重新登录。 - Show loading states - 登录/注册按钮要有 loading 状态和防抖。
- Clear error messages - 将错误码映射为用户可读的中文提示。
- SMS countdown - 发送验证码按钮增加倒计时,避免重复点击。
Performance
- SDK initialization - Always use synchronous initialization with
import cloudbase from "@cloudbase/js-sdk"; const app = cloudbase.init({ env: "xxxx-yyy" });, do not lazy-load SDK or wrap it in async helpers likeinitCloudBase() - Cache user data - 通过
await auth.getCurrentUser()获取用户实例后调用user.refresh(),避免重复请求。 - Batch operations - 使用一次
user.update()更新多个字段。
Example: Login form with validation
async function handleLogin(username, password) {
if (!username || !password) {
alert("请输入用户名和密码");
return;
}
const btn = document.getElementById("login-btn");
btn.disabled = true;
try {
await auth.signIn({ username, password });
window.location.href = "/app";
} catch (error) {
const messages = {
INVALID_CREDENTIALS: "用户名或密码错误",
RATE_LIMIT_EXCEEDED: "请求过于频繁,请稍后再试",
};
alert(messages[error.code] || "登录失败,请重试");
} finally {
btn.disabled = false;
}
}
Example: SMS login with countdown(正确拆分“发送验证码”和“验证码登录”)
let countdown = 0;
let lastVerificationInfo = null;
// Step 1: 只负责“发送验证码”
async function sendSmsCode(phoneNumber) {
if (countdown > 0) {
alert(`请等待 ${countdown} 秒后再试`);
return;
}
try {
lastVerificationInfo = await auth.getVerification({ phone_number: phoneNumber });
countdown = 60;
const timer = setInterval(() => {
countdown--;
updateButton();
if (countdown === 0) clearInterval(timer);
}, 1000);
} catch (error) {
alert("发送失败,请重试");
}
}
// Step 2: 只负责“携带验证码登录”,不要再调用 getVerification
async function loginWithSms(phoneNumber, verificationCode) {
if (!lastVerificationInfo) {
alert("请先获取验证码");
return;
}
try {
await auth.signInWithSms({
verificationInfo: lastVerificationInfo,
verificationCode,
phoneNum: phoneNumber,
});
// 登录成功,跳转或刷新页面
} catch (error) {
alert("登录失败,请重试");
}
}
function updateButton() {
const btn = document.getElementById("send-btn");
btn.disabled = countdown > 0;
btn.textContent = countdown > 0 ? `${countdown}秒后重试` : "发送验证码";
}
⚠️ 常见错误:把“发送验证码 + 验证码登录”一起封装成一个
login()函数,然后在 UI 上先点一次获取验证码、再点一次登录。第二次点击时如果再次执行getVerification,会刷新验证码或触发频率限制。正确做法是第二步直接调用signInWithSms,复用第一次返回的verificationInfo。
Summary
This skill covers all CloudBase Web Auth scenarios in one file:
- Login/user management scenarios - flat-listed with complete code
- Captcha handling - 说明如何处理
CAPTCHA_REQUIRED错误并交给 HTTP 层 - Error handling - 常见错误码和处理模式
- Best practices - 安全、UX、性能的实践示例
Key principle: 所有示例都基于 CloudBase 官方 Web SDK 接口,不自行发明 API。