Authentication: Web SDK
Frontend authentication using CloudBase Web SDK
How to Use
See How to Use Prompts for detailed usage instructions.
Test Prompts
You can use the following prompts to test:
- "Help me implement a Web login page using CloudBase Auth"
- "Create a user registration and login feature"
Prompt
rule.md
## 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)
1. **Confirm CloudBase environment**
- Ask the user for:
- `env` – CloudBase environment ID
- Always initialize the SDK in this pattern (update values only):
```js
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 as `initCloudBase()` with internal `initPromise`
2. **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`
- **Before implementing any login flow, you MUST:**
1. Guide the user to open the console login management page using the URL above
2. Confirm the required login methods are enabled(SMS / Email / Username/Password / WeChat Open Platform / Custom Login)
3. Confirm SMS/Email templates are configured(if using SMS/email login)
4. Confirm Current Web domain has been added to **Security Domain** (Security Source List)
- **If something is missing, explain clearly what the user must configure and provide the console URL.**
3. **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.
4. **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**.
5. **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.
---
## Installation and initialization
```bash
npm install --save @cloudbase/js-sdk
```
```js
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 internal `initPromise` caches
- Keep a single shared `app`/`auth` instance 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:**
1. **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`
2. **Enable required login methods:**
- Anonymous login (Anonymous login)
- SMS verification code login (SMS verification code login)
- Email verification code login (Email verification code login)
- Username/password login (Username/password login)
- WeChat Open Platform login (WeChat Open Platform login)
- Custom login (Custom login)
3. **Configure SMS/Email templates** (if using SMS/email login):
- Set up verification code templates in console
4. **Add Web domain to Security Source List (Security Domain Whitelist):**
- Go to: 云开发控制台 → 身份认证 → login methods → 安全域名
- 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 calls
- `refresh_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)
```js
// 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)
```js
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
```js
await auth.signIn({
username: "your username", // phone, email, or username
password: "your password",
});
```
### Scenario 4: Anonymous login
```js
await auth.signInAnonymously();
const loginScope = await auth.loginScope();
console.log(loginScope === "anonymous"); // true
```
### Scenario 5: Register new user (phone or email)
```js
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: "Mobile User", // optional
password: "password", // optional
username: "username", // optional
});
}
```
### Scenario 6: WeChat OAuth login (3 steps)
```js
// 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(Frontend and backend coordination)**
1. Backend (Node SDK) after verifying your own user system, use `app.auth().createTicket()` 生成Custom login ticket。
2. Frontend through `auth.setCustomSignFunc(getTicketFn)` tell Web SDK how to asynchronously get ticket。
3. Frontend calls `auth.signInWithCustomTicket()` complete login。
```js
// Backend (Node.js) Example
// 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 Example
import cloudbase from "@cloudbase/js-sdk";
const app = cloudbase.init({
env: "your-env-id",
});
const auth = app.auth();
// Define function to get custom ticket (from your backend)
const getTicketFn = async () => {
const res = await fetch("/api/get-custom-ticket");
const data = await res.json();
return data.ticket; // 后端returned from first time ticket 字符串
};
// 告诉 Web SDK 如何GetCustom login ticket
await auth.setCustomSignFunc(getTicketFn);
// Login with custom ticket
await auth.signInWithCustomTicket();
```
### Scenario 8: Upgrade anonymous user to registered
```js
// 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
```js
await auth.signOut();
```
### Scenario 10: Get current user
```js
const user = await auth.getCurrentUser();
if (user) {
console.log(user.uid, user.name, user.email, user.phone);
}
```
### Scenario 11: Update user profile (User.update)
```js
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**
1. 用户Logged in(可以Through `await auth.getCurrentUser()` Get到用户)。
2. Through `auth.sudo(...)` Get `sudo_token`:
- Can use current password, or SMS/email verification code。
3. 调用 `auth.setPassword({ new_password, sudo_token })` Update password。
```js
// 1. User enters current password
const oldPassword = "user_current_password";
// 2. Get sudo_token
const sudoRes = await auth.sudo({
password: oldPassword,
});
const sudoToken = sudoRes.sudo_token;
// 3. Set new password
await auth.setPassword({
new_password: "new_password",
sudo_token: sudoToken,
});
```
### Scenario 13: Reset password (forgot password)
```js
// 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**
1. 用户Logged in(可以Through `await auth.getCurrentUser()` Get到用户)。
2. Through `auth.genProviderRedirectUri` Get微信授权地址并跳转。
3. 在回调页Use `auth.grantProviderToken` Get `provider_token`。
4. 调用 `auth.bindWithProvider({ provider_token })` 将微信账号绑定到当前 CloudBase 账号。
```js
// 1. 在账号设置页点击“绑定微信”
// Generate WeChat authorization URL
const { uri } = await auth.genProviderRedirectUri({
provider_id: "wx_open",
provider_redirect_uri: "https://your-app.com/bind-callback",
state: "bind_wechat",
});
// Redirect to WeChat authorization
window.location.href = uri;
```
在回调页:
```js
// 2. WeChat callback page
const urlParams = new URLSearchParams(window.location.search);
const provider_code = urlParams.get("code");
// Exchange code for provider_token
const { provider_token } = await auth.grantProviderToken({
provider_id: "wx_open",
provider_redirect_uri: window.location.href,
provider_code,
});
// 3. Bind WeChat to current account
await auth.bindWithProvider({
provider_token,
});
```
---
### Scenario 15: List and unbind third-party providers
**CloudBase flow**
1. Use `auth.getProviders()` Get当前用户已绑定的三方列表。
2. Use `auth.unbindProvider({ provider_id })` Unbind。
```js
// Get绑定的三方账号列表
const providers = await auth.getProviders();
// providers: { id: string; name?: string; picture?: string; }[]
// Example: Unbind first provider
if (providers.length > 0) {
const first = providers[0];
await auth.unbindProvider({
provider_id: first.id,
});
}
```
> Note: Phone number/email binding/unbinding is currently completed through HTTP API. This Web SDK skill does not directly provide code. Please use HTTP Auth skill or backend Node SDK to implement.
---
### Scenario 16: Delete current account (Auth.sudo + Auth.deleteMe)
**CloudBase flow**
1. 用户Logged in。
2. Through `auth.sudo(...)` Get `sudo_token`(With password or verification code)。
3. Use `auth.deleteMe({ sudo_token })` Delete current account。
```js
// 1. 让User enters current password确认删除
const password = "user_current_password";
// 2. Get sudo_token
const sudoRes = await auth.sudo({ password });
const sudoToken = sudoRes.sudo_token;
// 3. Delete current account
await auth.deleteMe({
sudo_token: sudoToken,
});
// Current session ended, user has been deleted
```
---
### Scenario 17: Listen for login state changes (Auth.onLoginStateChanged)
**CloudBase flow**
- Use `app.auth().onLoginStateChanged(callback)` Listen for login state changes。
- 回调 `params.data.eventType` May be:`sign_in` / `sign_out` / `refresh_token_failed` 等。
- Note:`onLoginStateChanged` **Return value is `undefined`**,Does not return unsubscribe function or Promise; do not treat return value as cleanup handle or `await` it, just register listener once。
```js
app.auth().onLoginStateChanged((params) => {
console.log(params);
const { eventType } = params?.data || {};
switch (eventType) {
case "sign_in":
// Login successful
break;
case "sign_out":
// Logout
break;
case "refresh_token_failed":
// Token refresh failed, need to prompt user to re-login
break;
default:
break;
}
});
```
---
### Scenario 18: Get access token for backend verification
```js
const { accessToken, accessTokenExpire } = await auth.getAccessToken();
// Pass accessToken to your own backend via Authorization header
await fetch("/api/protected", {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
```
---
### Scenario 19: Refresh user data from server
```js
const user = await auth.getCurrentUser();
if (user) {
await user.refresh();
// user object now contains latest user information
console.log(user.name, user.picture);
}
```
---
## Captcha handling
### When captcha is triggered
CloudBase When abnormal frequency or risk control is triggered, will return **Send verification code / 登录** operations with `CAPTCHA_REQUIRED` error code。
Web SDK does not directly provide `getCaptcha` / `verifyCaptcha` methods, captcha image/verification is usually completed through **HTTP API**(例如:`Get图片验证码.api.mdx`、`验证图片验证码.api.mdx`)。
In frontend code, you should:
1. Catch `CAPTCHA_REQUIRED` error。
2. Prompt user to complete image captcha。
3. Call image captcha related APIs through HTTP Auth skill or backend service, and include `getVerification` / 登录in subsequent `captcha_token` and other information returned by backend。
Example (only shows error flow, does not show HTTP details):
```js
try {
await auth.getVerification({ phone_number: "+86 13800000000" });
} catch (error) {
if (error.code === "CAPTCHA_REQUIRED") {
// Prompt user to complete image captcha
// 具体实现:调用 HTTP 接口Get验证码图片并校验,参考 HTTP Auth skill
console.log("Image captcha required, please call HTTP captcha API");
}
}
```
### Rate limits(Refer to console configuration)
- **Verification code sending frequency**:Has frequency limits for same phone number/email, same IP。
- **Login failure count**:连续密码error会触发风控,需要稍后重试或走验证码流程。
---
## Error handling
### Common error codes
```js
try {
await auth.signIn({ username: "user", password: "wrong" });
} catch (error) {
console.error(error.code, error.message);
// 常见error code:
// INVALID_CREDENTIALS - 用户名或密码error
// VERIFICATION_CODE_EXPIRED - Verification code expired
// VERIFICATION_CODE_INVALID - 验证码error
// RATE_LIMIT_EXCEEDED - Frequency limit triggered
// CAPTCHA_REQUIRED - Image captcha required
// USER_NOT_FOUND - User not found
// USER_ALREADY_EXISTS - User already exists
}
```
---
## Best practices
### Security
1. **Always validate on server** - Frontend only handles UX, authentication should be done on backend based on `access_token` completed。
2. **Use HTTPS only** - Production environment must use HTTPS (except localhost)。
3. **Whitelist domains** - Add all frontend domains to console "Security Domain"。
4. **Re-auth for sensitive operations** - Before operations like deleting account, first call `auth.sudo` re-verify identity。
### UX
1. **Check existing login** - On page initialization, through `await auth.getCurrentUser()` Check current login state, avoid duplicate login。
2. **Handle session expiry** - Use `onLoginStateChanged` Listen for token expiration, prompt user to re-login。
3. **Show loading states** - Login/register buttons should have loading state and debounce。
4. **Clear error messages** - 将error code映射为用户可读的中文提示。
5. **SMS countdown** - Add countdown to send verification code button, avoid duplicate clicks。
### Performance
1. **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 like `initCloudBase()`
2. **Cache user data** - Through `await auth.getCurrentUser()` Get用户实例后调用 `user.refresh()`,Avoid duplicate requests。
3. **Batch operations** - Use一次 `user.update()` Update multiple fields。
### Example: Login form with validation
```js
async function handleLogin(username, password) {
if (!username || !password) {
alert("Please enter username and password");
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: "用户名或密码error",
RATE_LIMIT_EXCEEDED: "请求过于频繁,请稍后再试",
};
alert(messages[error.code] || "Login failed, please retry");
} finally {
btn.disabled = false;
}
}
```
### Example: SMS login with countdown(正确拆分“Send verification code”和“验证码登录”)
```js
let countdown = 0;
let lastVerificationInfo = null;
// Step 1: 只负责“Send verification code”
async function sendSmsCode(phoneNumber) {
if (countdown > 0) {
alert(`Please wait ${countdown} seconds before retrying`);
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("Send failed, please retry");
}
}
// Step 2: 只负责“携带验证码登录”,不要再调用 getVerification
async function loginWithSms(phoneNumber, verificationCode) {
if (!lastVerificationInfo) {
alert("请先Get验证码");
return;
}
try {
await auth.signInWithSms({
verificationInfo: lastVerificationInfo,
verificationCode,
phoneNum: phoneNumber,
});
// Login successful,跳转或刷新页面
} catch (error) {
alert("Login failed, please retry");
}
}
function updateButton() {
const btn = document.getElementById("send-btn");
btn.disabled = countdown > 0;
btn.textContent = countdown > 0 ? `${countdown}seconds before retry` : "Send verification code";
}
```
> ⚠️ 常见error:把“Send verification code + 验证码登录”一起封装成一个 `login()` 函数,然后在 UI 上先点一次Get验证码、再点一次登录。第二次点击时如果再次执行 `getVerification`,会刷新验证码或Frequency limit triggered。**正确做法是第二步直接调用 `signInWithSms`in second step, reuse `verificationInfo`。**
---
## Summary
This skill covers all CloudBase Web Auth scenarios in one file:
- **Login/user management scenarios** - flat-listed with complete code
- **Captcha handling** - Explains how to handle `CAPTCHA_REQUIRED` error并交给 HTTP 层
- **Error handling** - 常见error code和处理模式
- **Best practices** - Security, UX, performance practice examples
**Key principle:** All examples are based on CloudBase official Web SDK interfaces, do not invent APIs。