Awesome-omni-skill auth-web-cloudbase
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.
git clone https://github.com/diegosouzapw/awesome-omni-skill
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/development/auth-web-cloudbase-majiayu000" ~/.claude/skills/diegosouzapw-awesome-omni-skill-auth-web-cloudbase-fb429e && rm -rf "$T"
skills/development/auth-web-cloudbase-majiayu000/SKILL.mdWhen 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 (
, tokens) with your own backenduid - 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:
– CloudBase environment IDenv
-
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
or async wrappers such asimport("@cloudbase/js-sdk")
with internalinitCloudBase()initPromise
- 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
with the actual CloudBase environment ID (e.g.,{envId}
)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
with internalinitCloudBase()
cachesinitPromise - Keep a single shared
/app
instance in your frontend app; reuse it instead of re-initializingauth
⚠️ 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
with your actual CloudBase environment ID{envId} - 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:
(JWT, 2 hours) – for API callsaccess_token
(30 days) – auto-refreshed by SDKrefresh_token- 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)在验证完你自己用户系统后,使用
生成自定义登录 ticket。app.auth().createTicket() - 前端通过
告诉 Web SDK 如何异步获取 ticket。auth.setCustomSignFunc(getTicketFn) - 前端调用
完成登录。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 - 调用
将微信账号绑定到当前 CloudBase 账号。auth.bindWithProvider({ provider_token })
// 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
,不会返回取消订阅函数或 Promise;不要把返回值当作清理句柄或去undefined
它,只需要注册一次监听即可。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 - 使用
监听 token 失效,提示用户重新登录。onLoginStateChanged - Show loading states - 登录/注册按钮要有 loading 状态和防抖。
- Clear error messages - 将错误码映射为用户可读的中文提示。
- SMS countdown - 发送验证码按钮增加倒计时,避免重复点击。
Performance
- SDK initialization - Always use synchronous initialization with
, do not lazy-load SDK or wrap it in async helpers likeimport cloudbase from "@cloudbase/js-sdk"; const app = cloudbase.init({ env: "xxxx-yyy" });initCloudBase() - 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}秒后重试` : "发送验证码"; }
⚠️ 常见错误:把“发送验证码 + 验证码登录”一起封装成一个
函数,然后在 UI 上先点一次获取验证码、再点一次登录。第二次点击时如果再次执行login(),会刷新验证码或触发频率限制。正确做法是第二步直接调用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 - 说明如何处理
错误并交给 HTTP 层CAPTCHA_REQUIRED - Error handling - 常见错误码和处理模式
- Best practices - 安全、UX、性能的实践示例
Key principle: 所有示例都基于 CloudBase 官方 Web SDK 接口,不自行发明 API。