| name | auth-web-cloudbase |
| description | CloudBase Web Authentication Quick Guide for frontend integration after auth-tool has already been checked. Provides concise and practical Web authentication solutions with multiple login methods and complete user management. |
| version | 2.20.1 |
| alwaysApply | false |
Standalone Install Note
If this environment only installed the current skill, start from the CloudBase main entry and use the published cloudbase/references/... paths for sibling skills.
- CloudBase main entry:
https://cnb.cool/tencent/cloud/cloudbase/cloudbase-skills/-/git/raw/main/skills/cloudbase/SKILL.md
- Current skill raw source:
https://cnb.cool/tencent/cloud/cloudbase/cloudbase-skills/-/git/raw/main/skills/cloudbase/references/auth-web/SKILL.md
Keep local references/... paths for files that ship with the current skill directory. When this file points to a sibling skill such as auth-tool or web-development, use the standalone fallback URL shown next to that reference.
Activation Contract
Use this first when
- The task is a CloudBase Web login, registration, session, or user profile flow built with
@cloudbase/js-sdk and the auth provider setup has already been checked.
Read before writing code if
- The user needs a login page, auth modal, session handling, or protected Web route. Read
auth-tool first to ensure providers are enabled, then return here for frontend integration.
Then also read
../auth-tool/SKILL.md (standalone fallback: https://cnb.cool/tencent/cloud/cloudbase/cloudbase-skills/-/git/raw/main/skills/cloudbase/references/auth-tool/SKILL.md) for provider setup
../web-development/SKILL.md (standalone fallback: https://cnb.cool/tencent/cloud/cloudbase/cloudbase-skills/-/git/raw/main/skills/cloudbase/references/web-development/SKILL.md) for Web project structure and deployment
Do not start here first when
- The request is a Web auth flow but provider configuration has not been verified yet.
- In that case, activate
auth-tool-cloudbase before auth-web-cloudbase.
Do NOT use for
- Mini program auth, native App auth, or server-side auth setup.
Common mistakes / gotchas
-
Skipping publishable key and provider checks.
-
Replacing built-in Web auth with cloud function login logic.
-
Reusing this flow in Flutter, React Native, or native iOS/Android code.
-
Creating a detached helper file with auth.signUp / verifyOtp but never wiring it into the existing form handlers, so the actual button clicks still do nothing.
-
Using signInWithEmailAndPassword or signUpWithEmailAndPassword for username-style accounts such as admin and editor.
-
Keeping the login or register account input as type="email" when the task explicitly says the account identifier is a plain username string.
-
Starting implementation before calling queryAppAuth(action="getLoginConfig") and enabling usernamePassword when it is still off.
-
Treating auth.getUser() or deprecated auth.getLoginState() as proof of real login. When the SDK is initialized with accessKey, the deprecated getLoginState() returns an object with a valid uid even without any login — causing route guards that check !!loginState or !!uid to incorrectly pass. The fix is to use auth.getSession() instead: it returns data.session === undefined when no real login has occurred. Only !!data.session from getSession() is a reliable authentication check.
Note: anonymous login is now disabled by default for new environments and inactive existing environments. Always use auth.getSession() for auth guards.
Overview
Prerequisites: CloudBase environment ID (env)
Prerequisites: CloudBase environment Region (region)
Core Capabilities
Use Case: Web frontend projects using @cloudbase/js-sdk@2.24.0+ for user authentication
Key Benefits: Supabase-compatible Auth API — all methods return { data, error }, supports phone, email, anonymous (disabled by default), username/password, OAuth, and third-party login methods
📌 Supabase API Compatibility: CloudBase Web SDK v2 auth module is designed with Supabase-like API ergonomics. If you are familiar with supabase-js auth patterns, the same mental model applies:
- All methods return
Promise<{ data, error }> — always check error first
signInWithPassword, signInWithOtp, signUp, signOut, getSession, getUser follow the same naming as Supabase
onAuthStateChange(callback) provides reactive auth state observation (events: INITIAL_SESSION, SIGNED_IN, SIGNED_OUT, TOKEN_REFRESHED, USER_UPDATED, PASSWORD_RECOVERY, BIND_IDENTITY)
- Session management via
getSession() / refreshSession() / setSession() mirrors Supabase patterns
Key differences from Supabase:
- OTP verification: Supabase uses a standalone
auth.verifyOtp({ phone, token, type }) call; CloudBase returns verifyOtp as a callback on data — call data.verifyOtp({ token }) from the signInWithOtp / signUp result
accessKey replaces Supabase's anonKey; environment uses env + region instead of Supabase's url
signInWithIdToken for direct third-party token login (similar to Supabase's same-named method)
Use npm installation for modern Web projects. In React, Vue, Vite, and other bundler-based apps, install and import @cloudbase/js-sdk from the project dependencies instead of using a CDN script.
Prerequisites
- Automatically use
auth-tool-cloudbase to check app-side auth readiness via queryAppAuth / manageAppAuth, then get the publishable key and configure login methods.
- If
auth-tool-cloudbase failed, let user go to https://tcb.cloud.tencent.com/dev?envId={env}#/env/apikey to get publishable key and https://tcb.cloud.tencent.com/dev?envId={env}#/identity/login-manage to set up login methods
Parameter map
- For username-style identifiers, the required precondition is
loginMethods.usernamePassword === true from queryAppAuth(action="getLoginConfig"). If it is false, enable it with manageAppAuth(action="patchLoginStrategy", patch={ usernamePassword: true }) before wiring frontend auth code.
- If the conversation only provides an environment alias, nickname, or other shorthand, resolve it with
envQuery(action="list", alias=..., aliasExact=true) first and use the returned canonical full EnvId for SDK init, console links, and generated config. Do not pass alias-like short forms directly into cloudbase.init({ env }).
- Treat CloudBase Web Auth as Supabase-like, not “every
supabase-js auth example is valid unchanged”
- When
queryAppAuth / manageAppAuth returns sdkStyle: "supabase-like" and sdkHints, follow those method and parameter hints first
auth.signInWithOtp({ phone }) and auth.signUp({ phone }) use the phone number in a phone field, not phone_number
auth.signInWithOtp({ email }) and auth.signUp({ email }) use email
auth.signUp({ username, password }) and auth.signInWithPassword({ username, password }) are the canonical username/password Web auth path
- If the task gives accounts like
admin, editor, or another plain string without @, treat it as a username-style identifier rather than an email address
verifyOtp({ token }) expects the SMS or email code in token
accessKey is the publishable key from queryAppAuth / manageAppAuth via auth-tool-cloudbase, not a secret key
accessKey triggers automatic anonymous session creation — the deprecated auth.getLoginState() returns an object with a valid uid even without explicit login, which misleads route guards into thinking the user is authenticated. Use auth.getSession() instead — it returns data.session === undefined when no real login has occurred, making auth checks straightforward and reliable.
- Never set
accessKey to envId, a username, or any placeholder string. If you do not have a real Publishable Key yet, do not fabricate one.
- If the task mentions provider setup, stop and read
auth-tool-cloudbase before writing frontend code
Quick Start
import cloudbase from '@cloudbase/js-sdk'
const app = cloudbase.init({
env: 'your-full-env-id',
region: `region`,
accessKey: 'publishable key',
auth: { detectSessionInUrl: true },
})
const auth = app.auth({ persistence: 'local' })
If the current task has not retrieved a real Publishable Key, omit accessKey instead of inventing one. A wrong accessKey can break auth-state checks and protected-route behavior.
Login Methods
1. Phone OTP (Recommended)
- Automatically use
auth-tool-cloudbase to turn on SMS Login through manageAppAuth
- Send the phone number to
auth.signInWithOtp({ phone, ... }), then call the returned verifyOtp({ token }).
signInWithOtp can automatically create a new user if the user does not exist; control this via shouldCreateUser parameter (default true).
const { data, error } = await auth.signInWithOtp({ phone: '13800138000' })
const { data: loginData, error: loginError } = await data.verifyOtp({ token: '123456' })
2. Email OTP
- Automatically use
auth-tool-cloudbase to turn on Email Login through manageAppAuth
const { data, error } = await auth.signInWithOtp({ email: 'user@example.com' })
const { data: loginData, error: loginError } = await data.verifyOtp({ token: '654321' })
3. Password
All auth methods return { data, error }. Always check error first:
const { data, error } = await auth.signInWithPassword({ username: 'test_user', password: 'pass123' })
if (error) {
console.error('Login failed:', error.message)
return false
}
const uid = data.user.id
Checking login state (for route guards / auth checks):
const { data, error } = await auth.getSession()
if (!data?.session) {
window.location.href = '/login'
return
}
if (data.session.user?.is_anonymous) {
window.location.href = '/login'
return
}
const currentUser = data.session.user
const { data: userData } = await auth.getUser()
const hasVerifiedIdentity = userData?.user && (
userData.user.phone_confirmed_at ||
userData.user.email_confirmed_at ||
userData.user.user_metadata?.username
)
4. Registration
- For username-style account systems, use username/password registration directly
- Username must be 5-24 characters (letters, digits, underscores)
- Do not switch to email OTP or phone OTP unless the task explicitly says the account identifier is an email address or phone number
- When the task uses plain usernames such as
admin, editor, or user01, the canonical form code is auth.signUp({ username, password })
const usernameSignUp = await auth.signUp({
username: 'newuser',
password: 'pass123',
nickname: 'User',
})
const emailSignUp = await auth.signUp({ email: 'new@example.com', nickname: 'User' })
const emailVerifyResult = await emailSignUp.data.verifyOtp({ token: '123456' })
const phoneSignUp = await auth.signUp({ phone: '13800138000', password: 'pass123', nickname: 'User' })
const phoneVerifyResult = await phoneSignUp.data.verifyOtp({ token: '123456' })
When the project already has handleSendCode / handleRegister or similar UI handlers, wire the SDK calls there directly instead of leaving them commented out in App.tsx.
For username-style account tasks:
const handleRegister = async () => {
const { error } = await auth.signUp({
username,
password,
nickname: username,
})
if (error) throw error
}
const handleLogin = async () => {
const { data, error } = await auth.signInWithPassword({
username,
password,
})
if (error) throw error
return true
}
Do not use email OTP or email-only helpers for these flows unless the task explicitly says the account identifier is an email address. The corresponding form field should stay type="text" rather than type="email" for username-style account identifiers.
const handleSendCode = async () => {
try {
const { data, error } = await auth.signUp({
phone,
password: password || undefined,
})
if (error) throw error
verifyOtpRef.current = data.verifyOtp
} catch (error) {
console.error('Failed to send sign-up code', error)
}
}
const handleRegister = async () => {
try {
if (!verifyOtpRef.current) throw new Error('Please send the code first')
const { error } = await verifyOtpRef.current({ token: code })
if (error) throw error
} catch (error) {
console.error('Failed to complete sign-up', error)
}
}
5. Anonymous
⚠️ Anonymous login is disabled by default for new environments. The SDK initialized with accessKey will automatically create an anonymous session regardless of this setting. Do not rely on signInAnonymously() for production flows — use verified login methods instead.
- Only use when explicitly required for read-only demos
- Automatically use
auth-tool-cloudbase to turn on Anonymous Login through manageAppAuth (must be explicitly enabled first)
const { data, error } = await auth.signInAnonymously()
6. OAuth (Google/WeChat)
- Automatically use
auth-tool-cloudbase to turn on Google Login or WeChat Login through manageAppAuth
const { data, error } = await auth.signInWithOAuth({ provider: 'google' })
window.location.href = data.url
7. Custom Ticket
await auth.signInWithCustomTicket(async () => {
const res = await fetch('/api/ticket')
return (await res.json()).ticket
})
8. ID Token (Third-party token validation)
const { data, error } = await auth.signInWithIdToken({
provider: 'wechat',
token: '<jwt-or-oauth-token>',
})
9. Upgrade Anonymous
const sessionResult = await auth.getSession()
const upgradeResult = await auth.signUp({
phone: '13800000000',
anonymous_token: sessionResult.data.session.access_token,
})
await upgradeResult.data.verifyOtp({ token: '123456' })
User Management
const signOutResult = await auth.signOut()
const userResult = await auth.getUser()
console.log(
userResult.data.user.email,
userResult.data.user.phone,
userResult.data.user.user_metadata?.nickName,
)
const updateProfileResult = await auth.updateUser({
nickname: 'New Name',
gender: 'MALE',
avatar_url: 'url',
})
const updateEmailResult = await auth.updateUser({ email: 'new@example.com' })
const verifyEmailResult = await updateEmailResult.data.verifyOtp({
email: 'new@example.com',
token: '123456',
})
const resetPasswordResult = await auth.resetPasswordForOld({
old_password: 'old',
new_password: 'new',
})
const reauthResult = await auth.reauthenticate()
const forgotPasswordResult = await reauthResult.data.updateUser({
nonce: '123456',
password: 'new',
})
const linkIdentityResult = await auth.linkIdentity({ provider: 'google' })
const identitiesResult = await auth.getUserIdentities()
const unlinkIdentityResult = await auth.unlinkIdentity({
provider: identitiesResult.data.identities[0].id,
})
const deleteMeResult = await auth.deleteMe({ password: 'current' })
const authStateSubscription = auth.onAuthStateChange((event, session, info) => {
})
const sessionResult = await auth.getSession()
await fetch('/api/protected', {
headers: { Authorization: `Bearer ${sessionResult.data.session?.access_token}` },
})
const refreshResult = await auth.refreshSession()
const setResult = await auth.setSession({ refresh_token: '<token-from-server>' })
const refreshUserResult = await auth.refreshUser()
User Type
declare type User = {
id: any
aud: string
role: string[]
email: any
email_confirmed_at: string
phone: any
phone_confirmed_at: string
confirmed_at: string
last_sign_in_at: string
app_metadata: {
provider: any
providers: any[]
}
user_metadata: {
name: any
picture: any
username: any
gender: any
locale: any
uid: any
nickName: any
avatarUrl: any
location: any
hasPassword: any
}
identities: any
created_at: string
updated_at: string
is_anonymous: boolean
}
Complete Example
class PhoneLoginPage {
async sendCode() {
const phone = document.getElementById('phone').value
if (!/^1[3-9]\d{9}$/.test(phone)) return alert('Invalid phone')
const { data, error } = await auth.signInWithOtp({ phone })
if (error) return alert('Send failed: ' + error.message)
this.verifyOtp = data.verifyOtp
document.getElementById('codeSection').style.display = 'block'
this.startCountdown(60)
}
async verifyCode() {
const code = document.getElementById('code').value
if (!code) return alert('Enter code')
if (!this.verifyOtp) return alert('Send the code first')
const { data, error } = await this.verifyOtp({ token: code })
if (error) return alert('Verification failed: ' + error.message)
console.log('Login successful:', data.user)
window.location.href = '/dashboard'
}
startCountdown(seconds) {
let countdown = seconds
const btn = document.getElementById('resendBtn')
btn.disabled = true
const timer = setInterval(() => {
countdown--
btn.innerText = `Resend in ${countdown}s`
if (countdown <= 0) {
clearInterval(timer)
btn.disabled = false
btn.innerText = 'Resend'
}
}, 1000)
}
}