﻿---
hide_table_of_contents: true
---

import TabItem from '@theme/TabItem';
import ApiIntro from '../components/ApiIntro';
import ParameterTable from '../components/ApiContainer';
import Tabs from '@theme/Tabs';

# 概述

Auth Api 提供了一套完整的认证相关功能，支持多种登录方式、用户管理和会话管理。Auth Api 按照功能用途分为 7 个类别。每个类别包含相关的 API 方法，方便开发者根据具体需求快速找到合适的接口。

:::info 提示
v3 版本在调用身份认证相关 API 时，使用的是 [`身份认证 HTTP API`](../../../http-api/auth/登录认证接口) 的开放能力。
:::

- [认证登录](#认证登录)：用户注册和登录相关的 API 方法，支持多种登录方式。
- [会话管理](#会话管理)：管理用户会话状态和令牌的 API 方法。
- [用户管理](#用户管理)：获取、更新和管理用户信息的 API 方法。
- [身份源管理](#身份源管理)：管理第三方身份源绑定和解绑的 API 方法。
- [密码管理](#密码管理)：密码重置和修改相关的 API 方法。
- [验证管理](#验证管理)：验证码发送、验证和重发相关的 API 方法。
- [其他工具](#其他工具)：其他辅助功能的 API 方法。

---

## 基础使用示例 {#basic-usage-examples}

<Tabs>
<TabItem value="1" label="初始化配置" default>

`Publishable Key` 可前往 [云开发平台/API Key 配置](https://tcb.cloud.tencent.com/dev#/env/apikey) 中生成

`auth.detectSessionInUrl` 为初始化可选参数，设置后可以自动检测 URL 中的 OAuth 参数（code、state），适用于[signInWithOAuth](#signinwithoauth)、[linkIdentity](#linkidentity)等使用场景

```js
import cloudbase from "@cloudbase/js-sdk";

// 初始化
const app = cloudbase.init({
  env: "your-env-id", // 替换为您的环境ID
  region: "ap-shanghai", // 地域，默认为上海
  accessKey: "", // 填入生成的 Publishable Key，
  auth: {
    detectSessionInUrl: true, // 可选：自动检测 URL 中的 OAuth 参数，适用于signInWithOAuth、linkIdentity
  },
});

const auth = app.auth;
```

</TabItem>
<TabItem value="2" label="登录状态检查" >

```typescript
// 检查登录状态
async function checkAuthStatus() {
  const { data, error } = await auth.getSession();

  if (error) {
    console.error("检查登录状态失败:", error.message);
    return false;
  }

  if (data.session) {
    console.log("用户已登录:", data.session.user);
    return true;
  } else {
    console.log("用户未登录");
    return false;
  }
}
```

</TabItem>

<TabItem value="3" label="用户注册流程" >

```typescript
// 用户注册示例（四步验证流程）
async function registerUser(email, password, verificationCode) {
  // 第一步：发送验证码
  const { data, error } = await auth.signUp({
    email: email,
    password: password,
  });

  if (error) {
    console.error("发送验证码失败:", error.message);
    return false;
  } else {
    console.log("验证码已发送，等待验证...");

    // 第二步：验证验证码并完成注册
    const { data: loginData, error: loginError } = await data.verifyOtp({
      token: verificationCode,
    });

    if (loginError) {
      console.error("验证失败:", loginError.message);
      return false;
    } else {
      console.log("注册成功:", loginData.user?.email);
      return true;
    }
  }
}
```

</TabItem>

<TabItem value="4" label="用户登出" >

```typescript
// 用户登出示例
async function logoutUser() {
  const { data, error } = await auth.signOut();

  if (error) {
    console.error("登出失败:", error.message);
    return false;
  } else {
    console.log("登出成功，会话已清除");
    return true;
  }
}
```

</TabItem>

<TabItem value="5" label="密码登录" >

```typescript
// 密码登录示例
async function loginWithPassword(email, password) {
  const { data, error } = await auth.signInWithPassword({
    email: email,
    password: password,
  });

  if (error) {
    console.error("登录失败:", error.message);
    return false;
  } else {
    console.log("登录成功:", data.user?.email);
    return true;
  }
}
```

</TabItem>

<TabItem value="6" label="认证状态监听" >

```typescript
// 监听认证状态变化
auth.onAuthStateChange((event, session, info) => {
  console.log("认证状态变化:", event);

  switch (event) {
    case "INITIAL_SESSION":
      console.log("初始会话已建立");
      if (session) {
        console.log("用户已登录:", session.user);
      } else {
        console.log("用户未登录");
      }
      break;

    case "SIGNED_IN":
      console.log("用户登录成功:", session.user);
      break;

    case "SIGNED_OUT":
      console.log("用户已登出");
      break;

    case "PASSWORD_RECOVERY":
      console.log("密码已重置");
      break;

    case "TOKEN_REFRESHED":
      console.log("令牌已刷新");
      break;

    case "USER_UPDATED":
      console.log("用户信息已更新");
      break;

    case "BIND_IDENTITY":
      console.log("身份源绑定结果");
      break;
  }
});
```

</TabItem>

<TabItem value="7" label="手机验证码登录" >

```typescript
// 完整的手机验证码登录页面实现
class PhoneLoginPage {
  constructor() {
    this.setupEventListeners();
  }

  // 设置事件监听
  setupEventListeners() {
    document.getElementById("sendCodeBtn").addEventListener("click", (e) => {
      e.preventDefault();
      this.sendVerificationCode();
    });

    document.getElementById("verifyCodeBtn").addEventListener("click", (e) => {
      e.preventDefault();
      this.verifyCodeAndLogin();
    });
  }

  // 发送验证码
  async sendVerificationCode() {
    const phone = document.getElementById("phone").value;

    if (!phone) {
      alert("请输入手机号码");
      return;
    }

    // 验证手机号格式
    if (!this.validatePhone(phone)) {
      alert("请输入正确的手机号码格式");
      return;
    }

    try {
      const { data, error } = await auth.signInWithOtp({
        phone: phone,
      });

      if (error) {
        this.handleSendCodeError(error);
      } else {
        this.handleSendCodeSuccess(data);
      }
    } catch (error) {
      this.handleNetworkError(error);
    }
  }

  // 验证验证码并登录
  async verifyCodeAndLogin() {
    const code = document.getElementById("code").value;

    if (!code) {
      alert("请输入验证码");
      return;
    }

    if (!this.verifyFunction) {
      alert("请先发送验证码");
      return;
    }

    try {
      const { data, error } = await this.verifyFunction({ token: code });

      if (error) {
        this.handleVerifyError(error);
      } else {
        this.handleLoginSuccess(data);
      }
    } catch (error) {
      this.handleNetworkError(error);
    }
  }

  // 手机号格式验证
  validatePhone(phone) {
    const phoneRegex = /^1[3-9]\d{9}$/;
    return phoneRegex.test(phone);
  }

  // 处理发送验证码成功
  handleSendCodeSuccess(data) {
    this.verifyFunction = data.verifyOtp;

    // 显示验证码输入区域
    document.getElementById("verificationSection").style.display = "block";
    document.getElementById("phoneSection").style.display = "none";

    // 开始倒计时
    this.startCountdown(60);

    document.getElementById("success").innerText =
      "验证码已发送到您的手机，请注意查收";
    document.getElementById("success").style.display = "block";
  }

  // 处理发送验证码错误
  handleSendCodeError(error) {
    console.error("发送验证码失败:", error.code, error.category, error.message);
    switch (error.code) {
      case "invalid_argument":
        console.error(error.message || "手机号格式错误，请检查后重试");
        break;
      case "not_found":
        console.error("该手机号未注册，请先注册或使用其他手机号");
        break;
      case "resource_exhausted":
        console.error("发送频率过高，请稍后再试");
        break;
      case "unreachable":
        console.error("网络连接失败，请检查网络设置");
        break;
      default:
        console.error("发送验证码失败:", error.message);
    }
  }

  // 处理验证错误
  handleVerifyError(error) {
    console.error("验证失败:", error.code, error.category, error.message);
    switch (error.code) {
      case "invalid_argument":
        // 验证码过期/不正确/不匹配
        console.error(error.message || "验证码已过期或不正确，请重新获取");
        break;
      case "unauthenticated":
        // Token 失效，需要重新登录
        console.error("登录已过期，请重新登录");
        window.location.href = "/login";
        break;
      case "failed_precondition":
        console.error(error.message);
        break;
      case "not_found":
        console.error("用户不存在");
        break;
      case "unavailable":
        console.error("服务暂不可用，请稍后再试");
        break;
      case "unreachable":
        console.error("网络连接失败，请检查网络设置");
        break;
      default:
        console.error("验证失败:", error.message);
    }
  }

  // 处理登录成功
  handleLoginSuccess(data) {
    document.getElementById("success").innerText = "登录成功！欢迎回来";
    document.getElementById("success").style.display = "block";

    console.log("用户信息:", data.user);
    console.log("会话信息:", data.session);

    // 延迟跳转到首页
    setTimeout(() => {
      window.location.href = "/dashboard";
    }, 2000);
  }

  // 处理网络错误
  handleNetworkError(error) {
    console.error("网络错误，请检查网络连接后重试:", error);
  }

  // 开始倒计时
  startCountdown(seconds) {
    let countdown = seconds;
    const btn = document.getElementById("resendBtn");
    const originalText = btn.innerText;

    btn.disabled = true;

    const timer = setInterval(() => {
      countdown--;
      btn.innerText = `${countdown}秒后可重发`;

      if (countdown <= 0) {
        clearInterval(timer);
        btn.disabled = false;
        btn.innerText = originalText;
      }
    }, 1000);
  }
}

// 页面加载完成后初始化
window.addEventListener("DOMContentLoaded", () => {
  new PhoneLoginPage();
});
```

</TabItem>
</Tabs>

---

## 认证登录

## signUp

```typescript
async signUp(params: SignUpReq): Promise<SignUpRes>
```

注册新用户账户，采用智能注册并登录流程。

:::info 提示
`手机号验证码注册` 仅支持 `上海` 地域
:::

:::tip `messageId` 必填差异
成功后使用返回的 `data.verifyOtp({ token })` 校验即可，**不必传 `messageId`**（与 `signInWithOtp` 返回的回调相同，SDK 已绑定）。独立调用 `auth.verifyOtp` 时 `messageId` 为必填。
:::

- 创建一个新的用户账户
- 采用智能注册并登录流程：发送验证码 → 等待用户输入 → 智能判断用户存在性 → 自动登录或注册并登录
- 如果用户已存在则直接登录，如果用户不存在则注册新用户并自动登录

<ApiIntro parameter={{
input: [
{
name: "params",
type: "SignUpReq",
children: [{
name: "email",
type: "string",
description: "邮箱（与手机号二选一）",
},
{
name: "phone",
type: "string",
description: "手机号（与邮箱二选一）",
},
{
name: "password",
type: "string",
description: "密码",
},
{
name: "username",
type: "string",
description:
"用户名称，长度 5-24 位，支持英文大小写、数字、特殊字符（仅支持-_.:+ @），且只能以字母或数字开头，不支持中文",
},
{
name: "anonymous_token",
type: "string",
description: "匿名用户 access_token，用于匿名用户转正",
},]
}
],
output: [{
name: "Promise",
type: "SignUpRes",
children: [{
name: "data",
type: "SignUpResData",
required: true,
description: "",
children: [
{
name: "verifyOtp",
type: "(params: verifyParams) => Promise<SignInRes>",
description: "校验验证码并完成登录/注册。只需传 token，不必传 messageId（SDK 已绑定）。与独立方法 auth.verifyOtp 不同：独立调用时 messageId 必填，且只登录不注册",
children: [{
name: "params",
type: "verifyParams",
required: true,
description: "回调入参。闭包已绑定 email/phone 与发码时的 messageId",
children: [
{
name: "token",
type: "string",
required: true,
description: "验证码",
},
{
name: "messageId",
type: "string",
description: "可选，覆盖闭包中的验证码 ID；一般无需传入。独立调用 auth.verifyOtp 时该字段必填",
}
]
},
{
name: "return",
type: "Promise<SignInRes>",
required: true,
description: "返回",children: [{
name: "data",
type: "SignInResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "用户详细信息，包含身份信息和元数据",
},
{
name: "session",
type: "Session",
required: true,
description: "会话信息，包含访问令牌和刷新令牌",
},
],
},{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
},
]
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]}]
}}
> 
<Tabs>
<TabItem value="1" label="邮箱注册" default>

```typescript
// 第一步：发送邮箱验证码并存储 verificationInfo
const { data, error } = await auth.signUp({
  email: "newuser@example.com",
  password: "securePassword123",
  username: "newuser",
});

if (error) {
  console.error("发送验证码失败:", error.message);
} else {
  console.log("验证码已发送到邮箱，等待用户输入...");

  // 第二步：等待用户输入验证码（通过 Promise 包装用户输入事件）
  const verificationCode = "123456"; // 用户输入的验证码

  // 第三步：智能验证流程（自动判断用户存在性）
  const { data: loginData, error: loginError } = await data.verifyOtp({
    token: verificationCode,
  });

  if (loginError) {
    console.error("验证失败:", loginError.message);
  } else {
    // 第四步：自动完成注册或登录
    console.log("操作成功，用户信息:", loginData.user);
    console.log("会话信息:", loginData.session);
    console.log(
      "系统已自动判断：",
      loginData.user?.email ? "新用户注册并登录" : "现有用户直接登录"
    );
  }
}
```

</TabItem>

<TabItem value="2" label="手机号注册" default>

```typescript
// 第一步：发送手机验证码
const { data, error } = await auth.signUp({
  phone: "13800138000",
  password: "mypassword",
});

if (error) {
  console.error("发送验证码失败:", error.message);
} else {
  console.log("验证码已发送到手机，等待用户输入...");

  // 第二步：等待用户输入验证码
  const verificationCode = "123456"; // 用户输入的验证码

  // 第三步：智能验证流程（自动判断用户存在性）
  const { data: loginData, error: loginError } = await data.verifyOtp({
    token: verificationCode,
  });

  if (loginError) {
    console.error("操作失败:", loginError.message);
  } else {
    // 系统自动判断：如果用户已存在则直接登录，如果不存在则注册新用户
    if (loginData.user?.phone) {
      console.log("现有用户直接登录成功，用户信息:", loginData.user);
    } else {
      console.log("新用户注册并登录成功，用户ID:", loginData.user?.id);
    }
    console.log("会话状态:", loginData.session ? "已登录" : "未登录");
  }
}
```

</TabItem>

<TabItem value="3" label="注册表单页面实现" default>

```typescript
let signUpVerify = null;

async function startRegistration(email, password) {
  const { data, error } = await auth.signUp({
    email: email,
    password: password,
  });

  if (error) {
    console.error("发送验证码失败:", error.code, error.category, error.message);
    return false;
  } else {
    console.log("验证码已发送，系统将自动判断您是注册新用户还是登录现有账户");
    signUpVerify = data.verifyOtp;
    return true;
  }
}

async function completeRegistration(verificationCode) {
  if (!signUpVerify) {
    console.error("注册流程未开始");
    return false;
  }

  const { data, error } = await signUpVerify({ token: verificationCode });

  if (error) {
    console.error("验证失败:", error.code, error.category, error.message);
    if (error.code === "invalid_argument") {
      console.error(error.message || "验证码已过期或不正确，请重新获取");
    } else if (error.code === "unauthenticated") {
      console.error("认证失效，请重新登录");
      window.location.href = "/login";
    } else {
      console.error("验证失败:", error.message);
    }
    return false;
  } else {
    // 智能判断结果反馈
    if (data.user?.created_at) {
      console.log("新用户注册成功，欢迎加入！");
    } else {
      console.log("登录成功，欢迎回来！");
    }
    return true;
  }
}

// 注册表单提交
document
  .getElementById("registerForm")
  .addEventListener("submit", async (e) => {
    e.preventDefault();

    const email = document.getElementById("email").value;
    const password = document.getElementById("password").value;
    const nickname = document.getElementById("nickname").value;

    await startRegistration(email, password, nickname);
  });

// 验证码表单提交
document
  .getElementById("verificationForm")
  .addEventListener("submit", async (e) => {
    e.preventDefault();

    const code = document.getElementById("verificationCode").value;
    await completeRegistration(code);
  });
```

</TabItem>

<TabItem value="4" label="错误处理" default>

```typescript
try {
  const { data, error } = await auth.signUp({
    email: "existing@example.com",
    password: "password123",
  });

  if (error) {
    switch (error.code) {
      case "already_exists":
        console.error("邮箱/手机号/用户名已被注册，请使用其他邮箱或直接登录");
        break;
      case "password_too_weak":
        console.error("密码强度不足，请使用更复杂的密码");
        break;
      case "invalid_argument":
        console.error("参数格式错误，请检查邮箱或手机号格式");
        break;
      case "resource_exhausted":
        console.error("注册频率过高，请稍后重试");
        break;
      case "unreachable":
        console.error("网络连接失败，请检查网络设置后重试");
        break;
      default:
        console.error("注册失败:", error.message);
    }
  } else {
    console.log("验证码发送成功");
  }
} catch (error) {
  console.error("网络错误:", error);
}
```

</TabItem>

<TabItem value="5" label="验证码验证错误处理" default>

```typescript
async function verifyRegistrationCode(code) {
  try {
    const { data, error } = await signUpCallback(code);

    if (error) {
      console.error("验证失败:", error.code, error.category, error.message);
      switch (error.code) {
        case "invalid_argument":
          // 验证码过期/不正确/参数缺失
          console.error(error.message || "验证码已过期或不正确，请重新获取");
          break;
        case "failed_precondition":
          // 账号已被绑定等业务校验
          console.error(error.message);
          break;
        case "unauthenticated":
          // Token 失效，需要重新登录
          console.error("认证失效，请重新登录");
          window.location.href = "/login";
          break;
        case "not_found":
          // 用户不存在
          console.error("用户不存在");
          break;
        case "unavailable":
          // 服务端异常
          console.error("服务暂不可用，请稍后再试");
          break;
        case "unreachable":
          console.error("网络连接失败");
          break;
        default:
          console.error("验证失败:", error.message);
      }
      return false;
    } else {
      console.log("注册成功");
      return true;
    }
  } catch (error) {
    console.error("网络错误:", error);
    return false;
  }
}
```

</TabItem>

</Tabs>
</ApiIntro>

---

## signInAnonymously

```typescript
async signInAnonymously(params?: SignInAnonymouslyCredentials): Promise<AuthResponse>
```

匿名登录，创建一个临时匿名用户账户。

- 创建一个临时匿名用户账户
- 无需提供任何身份验证信息
- 适合需要临时访问权限的场景
- 使用前，请确认已在[云开发平台/身份认证/注册配置](https://tcb.cloud.tencent.com/dev?envId=#/identity/login-manage)中开启允许匿名登录（默认开启）

<ApiIntro parameter={{
input: [
{
name: "params",
type: "SignInAnonymouslyCredentials",
children: [{
name: "provider_token",
type: "string",
description: "提供令牌，用于关联第三方平台身份",
},]
}
],
output: [{
name: "Promise",
type: "AuthResponse",
children: [{
name: "data",
type: "AuthResponseData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "匿名用户信息，包含 is_anonymous 标识",
},
{
name: "session",
type: "Session",
required: true,
description: "匿名会话信息，包含访问令牌和刷新令牌",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]}]
}}
> 
<Tabs>
<TabItem value="1" label="匿名登录" default>

```typescript
// 创建匿名用户
const { data, error } = await auth.signInAnonymously();

if (error) {
  console.error("匿名登录失败:", error.message);
  console.error("错误代码:", error.code);
} else {
  console.log("匿名登录成功");
  console.log("匿名用户ID:", data.user?.id);
  console.log("会话信息:", data.session);
  console.log("是否为匿名用户:", data.user?.is_anonymous);
}
```

</TabItem>

<TabItem value="2" label="错误处理" default>

```typescript
async function safeAnonymousLogin() {
  try {
    const { data, error } = await auth.signInAnonymously();

    if (error) {
      switch (error.code) {
        case "resource_exhausted":
          console.error("请求频率过高，请稍后重试");
          break;
        case "invalid_provider_token":
          console.error("第三方平台令牌无效，请检查令牌格式");
          break;
        case "provider_not_supported":
          console.error("不支持的第三方平台，请检查平台标识");
          break;
        case "unreachable":
          console.error("网络连接失败，请检查网络设置后重试");
          break;
        case "permission_denied":
          console.error("权限不足，请检查安全域名配置");
          break;
        default:
          console.error("匿名登录失败:", error.message);
      }
      return null;
    } else {
      console.log("匿名登录成功");
      return data;
    }
  } catch (error) {
    console.error("网络错误:", error);
    return null;
  }
}

// 使用安全登录函数
const result = await safeAnonymousLogin();
if (result) {
  console.log("登录成功，用户信息:", result.user);
}
```

</TabItem>

<TabItem value="3" label="匿名用户转正流程" default>

```typescript
// 第一步：匿名登录
const { data: anonymousData, error: anonymousError } =
  await auth.signInAnonymously();

if (anonymousError) {
  console.error("匿名登录失败:", anonymousError.message);
} else {
  console.log("匿名登录成功，准备升级为正式用户");

  // 第二步：绑定邮箱或手机号（示例：绑定邮箱）
  const { data: upgradeData, error: upgradeError } = await auth.signUp({
    email: "user@example.com",
    password: "securePassword123",
    anonymous_token: anonymousData.session?.access_token,
  });

  if (upgradeError) {
    console.error("升级失败:", upgradeError.message);
  } else {
    console.log("升级成功，请输入验证码完成身份验证");

    // 第三步：验证验证码
    const verificationCode = "123456";
    const { data: finalData, error: finalError } = await upgradeData.verifyOtp({
      token: verificationCode,
    });

    if (finalError) {
      console.error("验证失败:", finalError.code, finalError.category, finalError.message);
      if (finalError.code === "invalid_argument") {
        console.error(finalError.message || "验证码已过期或不正确，请重新获取");
      } else if (finalError.code === "unauthenticated") {
        console.error("认证失效，请重新登录");
      } else {
        console.error("验证失败:", finalError.message);
      }
    } else {
      console.log("匿名用户成功升级为正式用户");
      console.log("新用户信息:", finalData.user);
      console.log("是否为匿名用户:", finalData.user?.is_anonymous);
    }
  }
}
```

</TabItem>

</Tabs>
</ApiIntro>

---

## signInWithPassword

```typescript
async signInWithPassword(params: SignInWithPasswordCredentials): Promise<AuthResponse>
```

使用用户名、邮箱或手机号和密码登录。

- 支持用户名、邮箱、手机号配合密码三种登录方式（三选一）
- 使用前，请确认已在[云开发平台/身份认证/常规登录](https://tcb.cloud.tencent.com/dev?envId=#/identity/login-manage)中开启用户名密码登录（默认开启）

<ApiIntro parameter={{
input: [
{
name: "params",
type: "SignInWithPasswordCredentials",
children: [{
name: "username",
type: "string",
description: "用户名称，长度 5-24 位，支持英文大小写、数字、特殊字符（仅支持-_.:+ @），且只能以字母或数字开头，不支持中文（与邮箱、手机号三选一）",
},
{
name: "email",
type: "string",
description: "邮箱地址，用于邮箱登录方式（与用户名、手机号三选一）",
},
{
name: "phone",
type: "string",
description: "手机号码，用于手机号登录方式（与用户名、邮箱三选一）",
},
{
name: "password",
type: "string",
required: true,
description: "用户密码，支持密码强度验证和重试次数限制",
},
{
name: "captchaToken",
type: "string",
description: "验证码令牌",
},]
}
],
output: [{
name: "Promise",
type: "AuthResponse",
children: [{
name: "data",
type: "AuthResponseData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "用户详细信息，包含身份信息和元数据",
},
{
name: "session",
type: "Session",
required: true,
description: "会话信息，包含访问令牌和刷新令牌",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
},]
}]
}}
> 
<Tabs>
<TabItem value="1" label="用户名登录" default>

```typescript
const { data, error } = await auth.signInWithPassword({
  username: "testuser",
  password: "password123",
});

if (error) {
  console.error("登录失败:", error.message);
} else {
  console.log("登录成功，用户信息:", data.user);
  console.log("会话信息:", data.session);
}
```

</TabItem>

<TabItem value="2" label="邮箱登录" default>

```typescript
const { data, error } = await auth.signInWithPassword({
  email: "user@example.com",
  password: "mypassword",
});

if (error) {
  console.error("登录失败:", error.message);
} else {
  console.log("登录成功，用户ID:", data.user?.id);
}
```

</TabItem>

<TabItem value="3" label="手机号登录" default>

```typescript
const { data, error } = await auth.signInWithPassword({
  phone: "13800138000",
  password: "securepassword",
});

if (error) {
  console.error("登录失败:", error.code, error.message);
} else {
  console.log("登录成功，用户ID:", data.user?.id);
}
```

</TabItem>

<TabItem value="4" label="错误处理" default>

```typescript
try {
  const { data, error } = await auth.signInWithPassword({
    username: "wronguser",
    password: "wrongpassword",
  });

  if (error) {
    // 根据常见错误代码进行完整错误处理
    switch (error.code) {
      case "not_found":
        console.error("用户不存在，请检查用户名/邮箱/手机号是否正确");
        break;
      case "password_not_set":
        console.error("当前用户未设置密码，请使用验证码登录或第三方登录方式");
        break;
      case "invalid_password":
        console.error("密码不正确，请重新输入");
        break;
      case "user_pending":
        console.error("该用户未激活，请联系管理员激活账户");
        break;
      case "user_blocked":
        console.error("该用户被停用，请联系管理员");
        break;
      case "invalid_status":
        console.error("您已经超过了密码最大重试次数，请稍后重试");
        break;
      case "invalid_two_factor":
        console.error("二次验证码不匹配或已过时，请重新获取");
        break;
      case "unreachable":
        console.error("网络连接失败，请检查网络设置后重试");
        break;
      default:
        console.error("登录失败:", error.message);
    }
  } else {
    console.log("登录成功");
  }
} catch (error) {
  console.error("网络错误:", error);
}
```

</TabItem>

</Tabs>
</ApiIntro>

---

## signInWithOtp

```typescript
async signInWithOtp(params: SignInWithPasswordlessCredentials): Promise<AuthOtpResponse>
```

使用一次性密码（OTP）进行登录验证，支持邮箱和手机号验证。

:::info 提示
`短信验证码` 仅支持 `上海` 地域
:::

:::tip `messageId` 必填差异
推荐使用本方法返回的 `data.verifyOtp({ token })` 完成校验，**不必传 `messageId`**（SDK 已在回调闭包中缓存发码时的 ID）。

若走 `getVerification` 发码后再调用独立方法 `auth.verifyOtp`，则 **`messageId` 必填**，取值来自 `getVerification` 返回的 `verification_id`。两条路径不要混用。
:::

- 通过邮箱或手机号发送一次性验证码进行登录验证
- 支持完整的验证流程：发送验证码 → 等待用户输入 → 验证并登录
- 适用于无密码登录场景，提供更高的安全性
- 使用前，请确认已在[云开发平台/身份认证/登录方式/常规登录](https://tcb.cloud.tencent.com/dev?envId=#/identity/login-manage)中开启邮箱/短信验证码登录
- 如果用户不存在，会默认注册用户，可以通过 `shouldCreateUser`参数控制是否自动创建用户，默认为 true
- 对于邮箱登录，可以通过 `emailRedirectTo` 参数指定回调地址，启用魔法链接（Magic Link）登录，用户点击邮件中的链接即可完成登录

<ApiIntro parameter={{
input: [
{
name: "params",
type: "SignInWithPasswordlessCredentials",
children: [{
name: "email",
type: "string",
description: "邮箱地址，用于邮箱验证码登录（与手机号二选一）",
},
{
name: "phone",
type: "string",
description: "手机号码，用于手机验证码登录（与邮箱二选一）",
},
{
name: "options",
type: "SignInWithPasswordlessOptions",
description: "可选项",
children: [{
name: "shouldCreateUser",
type: "boolean",
description: "如果用户不存在是否创建用户，默认为true",
},
{
name: "emailRedirectTo",
type: "string",
description: "邮箱魔法链接回调地址，填写后发送认证链接至邮箱，否则发送验证码。用户点击链接后会根据邮箱自动登录，登录成功后跳转到该回调地址",
}]
}]
}
],
output: [{
name: "Promise",
type: "AuthOtpResponse",
children: [{
name: "data",
type: "AuthOtpResponseData",
required: true,
description: "",
children: [
{
name: "verifyOtp",
type: "(params: verifyParams) => Promise<SignInRes>",
description: "校验验证码并完成登录/注册。只需传 token，不必传 messageId（SDK 已绑定）。与独立方法 auth.verifyOtp 不同：独立调用时 messageId 必填，且只登录不注册",
children: [{
name: "params",
type: "verifyParams",
required: true,
description: "回调入参。闭包已绑定 email/phone 与发码时的 messageId",
children: [
{
name: "token",
type: "string",
required: true,
description: "验证码",
},
{
name: "messageId",
type: "string",
description: "可选，覆盖闭包中的验证码 ID；一般无需传入。独立调用 auth.verifyOtp 时该字段必填",
}
]
},
{
name: "return",
type: "Promise<SignInRes>",
required: true,
description: "返回",children: [{
name: "data",
type: "SignInResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "用户详细信息，包含身份信息和元数据",
},
{
name: "session",
type: "Session",
required: true,
description: "会话信息，包含访问令牌和刷新令牌",
},
]
},{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
},
]
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]}]
}}
> 
<Tabs>
<TabItem value="1" label="手机验证码登录" default>

```typescript
const { data, error } = await auth.signInWithOtp({
  phone: "13800138000",
});

if (error) {
  console.error("发送验证码失败:", error.message);
} else {
  console.log("验证码已发送，等待用户输入...");

  // 用户输入验证码后验证
  const { data: loginData, error: loginError } = await data.verifyOtp({
    token: "123456",
  });

  if (loginError) {
    console.error("验证失败:", loginError.message);
  } else {
    console.log("登录成功:", loginData.user);
    console.log("会话信息:", loginData.session);
  }
}
```

</TabItem>

<TabItem value="2" label="邮箱验证码登录" default>

```typescript
// 发送邮箱验证码
const { data, error } = await auth.signInWithOtp({
  email: "user@example.com",
});

if (error) {
  console.error("发送验证码失败:", error.message);
} else {
  console.log("邮箱验证码已发送，请查收邮件...");

  // 用户从邮箱获取验证码后验证
  const { data: loginData, error: loginError } = await data.verifyOtp({
    token: "654321",
  });

  if (loginError) {
    console.error("验证失败:", loginError.message);
  } else {
    console.log("邮箱登录成功:", loginData.user?.email);
  }
}
```

</TabItem>

<TabItem value="3" label="关闭自动注册" default>

```typescript
const { data, error } = await auth.signInWithOtp({
  phone: "13800138000",
  options: {
    shouldCreateUser: false,
  },
});

if (error) {
  console.error("发送验证码失败:", error.message);
} else {
  console.log("验证码已发送，等待用户输入...");

  // 用户输入验证码后验证
  const { data: loginData, error: loginError } = await data.verifyOtp({
    token: "123456",
  });

  // 未注册用户会提示"user not exist"
}
```

</TabItem>

<TabItem value="4" label="邮箱魔法链接登录">

发送魔法链接：

```typescript
// 发送魔法链接至邮箱
const { data, error } = await auth.signInWithOtp({
  email: "user@example.com",
  options: {
    emailRedirectTo: "https://example.com/callback",
  },
});

if (error) {
  console.error("发送魔法链接失败:", error.message);
} else {
  console.log("魔法链接已发送至邮箱，请查收邮件并点击链接完成登录");
  // 用户点击邮件中的链接后，SDK 会自动完成登录并跳转到 https://example.com/callback
}
```

在回调页面中获取登录状态：

```typescript
// 在 emailRedirectTo 指定的回调页面中
// SDK 已自动完成登录，直接获取登录状态即可
import cloudbase from "@cloudbase/js-sdk";

const auth = cloudbase.auth();

// 监听认证状态变化
const { data } = auth.onAuthStateChange((event, session, info) => {
  if (event === "SIGNED_IN" && session) {
    console.log("登录成功:", session.user);
  } else if (event === "SIGNED_OUT") {
    console.log("已登出");
  }
});

// 取消监听（可选）
// data.subscription.unsubscribe();

// 或者主动获取会话
const { data, error } = await auth.getSession();
if (error) {
  console.error("获取会话失败:", error.message);
} else if (data.session) {
  console.log("当前用户:", data.session.user);
}
```

</TabItem>

<TabItem value="5" label="错误处理" default>

```typescript
try {
  const { data, error } = await auth.signInWithOtp({
    phone: "13800138000",
  });

  if (error) {
    switch (error.code) {
      case "resource_exhausted":
        console.error("发送频率过高，请稍后再试");
        break;
      case "invalid_argument":
        console.error("手机号或邮箱格式错误，请检查后重试");
        break;
      case "failed_precondition":
        console.error("从第三方获取用户信息失败，请重试");
        break;
      case "aborted":
        console.error("尝试次数过多，请返回首页，稍后重试");
        break;
      case "permission_denied":
        console.error("您当前的会话已过期，请返回重试");
        break;
      case "captcha_required":
        console.error("需要输入验证码，请根据反机器人服务接入");
        break;
      case "captcha_invalid":
        console.error("验证码不正确，请根据反机器人服务接入");
        break;
      case "unreachable":
        console.error("网络连接失败，请检查网络设置后重试");
        break;
      default:
        console.error("发送验证码失败:", error.message);
    }
    return;
  }

  // 验证验证码
  const { data: loginData, error: loginError } = await data.verifyOtp({
    token: "123456",
  });

  if (loginError) {
    console.error("验证失败:", loginError.code, loginError.category, loginError.message);
    switch (loginError.code) {
      case "invalid_argument":
        // 验证码过期/不正确/不匹配，提示重新获取
        console.error(loginError.message || "验证码已过期或不正确，请重新获取");
        break;
      case "unauthenticated":
        // Token 失效，需要重新登录
        console.error("认证失效，请重新登录");
        window.location.href = "/login";
        break;
      case "failed_precondition":
        // 账号已被绑定等
        console.error(loginError.message);
        break;
      case "not_found":
        console.error("用户不存在");
        break;
      case "unavailable":
        console.error("服务暂不可用，请稍后再试");
        break;
      default:
        console.error("验证失败:", loginError.message);
    }
  } else {
    console.log("登录成功");
  }
} catch (error) {
  console.error("网络错误:", error);
}
```

</TabItem>

</Tabs>
</ApiIntro>

---

## signInWithOAuth

```typescript
async signInWithOAuth(params: SignInWithOAuthCredentials): Promise<OAuthResponse>
```

生成第三方平台授权链接，支持微信、Google 等主流平台。

- 生成第三方平台（如微信、Google 等）的授权页面 URL
- 将状态信息保存到浏览器会话中，以便后续验证
- 支持自定义回调地址和状态参数
- 使用前，请确认已在[云开发平台/身份认证/登录方式](https://tcb.cloud.tencent.com/dev?envId=#/identity/login-manage)中开启对应的 OAuth 身份源

**注意事项**

- 调用此方法后，状态信息会自动保存到浏览器会话中，在 cloudbase.init 时设置`auth.detectSessionInUrl`为 `true` 时，从第三方回调回来后会自动调用 [verifyOAuth](#verifyoauth) 进行验证，否则后续需要手动通过 [verifyOAuth](#verifyoauth) 方法进行验证
- 如果未提供 state 参数，系统会自动生成格式为`prd-{provider}-{随机字符串}`的状态参数
- 回调地址需要配置在云开发平台的安全域名中，否则会返回权限错误
- 目前，使用"微信开放平台"登录时先要确保用户已关联对应的身份源，可以通过 [linkIdentity](#linkidentity) 进行身份源关联

<ApiIntro parameter={{
input: [
{
name: "params",
type: "SignInWithOAuthCredentials",
children: [{
name: "provider",
type: "string",
required: true,
description: "第三方平台标识，支持 wechat、google、github、facebook、apple 等",
},
{
name: "options",
type: "SignInWithOAuthOptions",
description: "配置选项",
children: [
{
name: "redirectTo",
type: "string",
description: "回调地址，默认为当前页面，需要配置在安全域名中",
},
{
name: "state",
type: "string",
description: "状态参数，用于安全验证，默认为随机字符串（格式：prd-{provider}-{随机字符串}）",
},
{
name: "queryParams",
type: "Record<string, string>",
description: "额外的查询参数，将合并到授权 URI 中",
},
{
name: "skipBrowserRedirect",
type: "boolean",
description: "是否跳转至授权页面，默认为false",
},
{
name: "type",
type: "'sign_in' | 'bind_identity'",
description: "类型（可选），默认为'sign_in', sign_in: 登录，bind_identity: 绑定身份",
},
],
},]
}
],
output: [{
name: "Promise",
type: "OAuthResponse",
children: [{
name: "data",
type: "OAuthResponseData",
required: true,
description: "",
children: [
{
name: "url",
type: "string",
required: true,
description: "授权页面 URL，用于跳转到第三方平台授权页面",
},
{
name: "provider",
type: "string",
required: true,
description: "第三方平台标识，用于后续验证和状态管理",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]}]
}}
> 
<Tabs>
<TabItem value="1" label="微信授权登录" default>

```typescript
// 初始化
const app = cloudbase.init({
  env: "your-env-id", // 替换为您的环境ID
  region: "ap-shanghai", // 地域，默认为上海
  accessKey: "", // 填入生成的 Publishable Key，
  auth: {
    detectSessionInUrl: true, // 可选：自动检测 URL 中的 OAuth 参数
  },
});

const { data, error } = await auth.signInWithOAuth({
  provider: "wechat",
  options: {
    redirectTo: "https://example.com/callback",
    state: "wx_auth_123456",
  },
});

if (error) {
  console.error("获取微信授权链接失败:", error.message);
} else {
  console.log("微信授权链接:", data.url);
  console.log("第三方平台:", data.provider);
  // 跳转到微信授权页面
  window.location.href = data.url;
}
```

</TabItem>

<TabItem value="2" label="Google授权登录" default>

```typescript
const app = cloudbase.init({
  env: "your-env-id", // 替换为您的环境ID
  region: "ap-shanghai", // 地域，默认为上海
  accessKey: "", // 填入生成的 Publishable Key，
  auth: {
    detectSessionInUrl: true, // 可选：自动检测 URL 中的 OAuth 参数
  },
});

const auth = app.auth;

const { data, error } = await auth.signInWithOAuth({
  provider: "google",
});

if (error) {
  console.error("获取Google授权链接失败:", error.message);
} else {
  console.log("Google授权链接已生成，准备跳转...");
  console.log("授权URL:", data.url);
  // 在新窗口打开授权页面
  window.open(data.url, "_blank");
}
```

</TabItem>

<TabItem value="3" label="OAuth 登录最佳实践" default>

```typescript
// OAuth登录最佳实践 - 完整的UI交互流程
// 初始化
const app = cloudbase.init({
  env: "your-env-id", // 替换为您的环境ID
  region: "ap-shanghai", // 地域，默认为上海
  accessKey: "", // 填入生成的 Publishable Key，
  auth: {
    detectSessionInUrl: true, // 可选：自动检测 URL 中的 OAuth 参数，适用于signInWithOAuth、linkIdentity
  },
});

// 修改认证状态变化监听器，添加浮窗显示
async function setupAuthStateChangeListener() {
  try {
    if (!app.auth) return;

    // 订阅认证状态变化事件
    const { data } = await app.auth.onAuthStateChange(
      (event, session, info) => {
        console.log("认证状态变化:", { event, session, info });

        switch (event) {
          case "SIGNED_IN":
            if (session && session.user) {
              console.log("登录成功！");
            }
            break;

          default:
            console.log("未知认证事件:", event);
        }
      }
    );

    console.log("认证状态变化监听器已设置");
  } catch (error) {
    console.error("设置认证状态变化监听器失败:", error);
  }
}

class OAuthManager {
  constructor() {
    this.initEventListeners();
    this.provider = "oauth";
  }

  // 初始化事件监听器
  initEventListeners() {
    // OAuth登录按钮点击事件
    document.getElementById("oauth-login-btn").addEventListener("click", () => {
      this.startOAuth();
    });
  }

  // 开始OAuth授权流程
  async startOAuth() {
    try {
      this.showLoading(true);
      this.hideError();

      const { data, error } = await auth.signInWithOAuth({
        provider: this.provider,
      });

      if (error) {
        this.handleOAuthError(error);
      } else {
        console.log("OAuth授权链接生成成功，正在跳转...");

        // 最佳实践：使用当前窗口跳转，保持用户体验
        window.location.href = data.url;
      }
    } catch (error) {
      this.handleOAuthError(error);
    } finally {
      this.showLoading(false);
    }
  }

  showLoading(show) {
    document.getElementById("loading").style.display = show ? "block" : "none";
  }
}

setupAuthStateChangeListener();
// 初始化OAuth登录管理器
const oAuthManager = new OAuthManager();
```

</TabItem>

<TabItem value="4" label="手动处理 OAuth回调（不推荐）" default>

```typescript
// 初始化
const app = cloudbase.init({
  env: "your-env-id", // 替换为您的环境ID
  region: "ap-shanghai", // 地域，默认为上海
  accessKey: "", // 填入生成的 Publishable Key，
});

class OAuthManager {
  constructor() {
    this.initEventListeners();
    this.provider = "oauth";
  }

  // 初始化事件监听器
  initEventListeners() {
    // OAuth登录按钮点击事件
    document.getElementById("oauth-login-btn").addEventListener("click", () => {
      this.startOAuth();
    });

    // 页面加载时检查是否有OAuth授权回调
    document.addEventListener("DOMContentLoaded", () => {
      this.checkOAuthCallback();
    });
  }

  // 开始OAuth授权流程
  async startOAuth() {
    try {
      this.showLoading(true);
      this.hideError();

      const { data, error } = await auth.signInWithOAuth({
        provider: this.provider,
      });

      if (error) {
        this.handleOAuthError(error);
      } else {
        console.log("OAuth授权链接生成成功，正在跳转...");

        // 最佳实践：使用当前窗口跳转，保持用户体验
        window.location.href = data.url;
      }
    } catch (error) {
      this.handleOAuthError(error);
    } finally {
      this.showLoading(false);
    }
  }

  // 检查OAuth授权回调
  async checkOAuthCallback() {
    const urlParams = new URLSearchParams(window.location.search);
    const code = urlParams.get("code");
    const state = urlParams.get("state");

    if (code && state) {
      console.log("检测到OAuth授权回调，正在验证...");
      await this.verifyOAuth(code, state);
    }
  }

  // 验证OAuth授权
  async verifyOAuth(code, state) {
    try {
      this.showLoading(true);

      const result = await auth.verifyOAuth({
        code: code,
        state: state,
        provider: this.provider,
      });

      if (result.error) {
        this.handleOAuthError(result.error);
      } else {
        console.log("OAuth登录成功！");
        this.showSuccess("OAuth登录成功！");
      }
    } catch (error) {
      this.handleOAuthError(error);
    } finally {
      this.showLoading(false);
    }
  }

  // 错误处理
  handleOAuthError(error) {
    console.error("OAuth登录错误:", error);

    switch (error.code) {
      case "provider_not_supported":
        this.showError("不支持的第三方平台，请检查平台标识是否正确");
        break;
      case "invalid_redirect_uri":
        this.showError("回调地址格式错误，请检查URL格式");
        break;
      case "failed_precondition":
        this.showError("从OAuth获取用户信息失败，请检查平台配置");
        break;
      case "permission_denied":
        this.showError("权限不足，请检查安全域名配置");
        break;
      case "resource_exhausted":
        this.showError("请求频率过高，请稍后重试");
        break;
      case "unreachable":
        this.showError("网络连接失败，请检查网络设置后重试");
        break;
      case "invalid_code":
        this.showError("授权码无效或已过期，请重新授权");
        break;
      case "state_mismatch":
        this.showError("状态参数不匹配，可能存在安全风险，请重新授权");
        break;
      default:
        this.showError("OAuth登录失败：" + (error.message || "未知错误"));
    }
  }

  showLoading(show) {
    document.getElementById("loading").style.display = show ? "block" : "none";
  }

  showError(message) {
    const errorElement = document.getElementById("error-message");
    errorElement.textContent = message;
    errorElement.style.display = "block";
  }

  hideError() {
    document.getElementById("error-message").style.display = "none";
  }

  showSuccess(message) {
    const successElement = document.getElementById("success-message");
    successElement.textContent = message;
    successElement.style.display = "block";
  }
}
```

</TabItem>

</Tabs>
</ApiIntro>

---

## signInWithIdToken

```typescript
async signInWithIdToken(params: SignInWithIdTokenReq): Promise<SignInRes>
```

使用第三方平台的身份令牌登录，支持微信、Google 等主流平台。

- 使用第三方平台（如微信、Google 等）的身份令牌进行登录
- 支持指定第三方平台标识，第三方平台需在[云开发平台/身份认证/登录方式](https://tcb.cloud.tencent.com/dev?envId=#/identity/login-manage)中先进行配置配置
- 令牌为必填参数

<ApiIntro parameter={{
input: [
{
name: "params",
type: "SignInWithIdTokenReq",
children: [{
name: "provider",
type: "string",
description: "第三方平台标识，支持 wechat、google、github、facebook、apple 等，不指定时使用通用令牌验证",
},
{
name: "token",
type: "string",
required: true,
description: "第三方平台的身份令牌，支持 JWT、OAuth 令牌等多种格式",
},]
}
],
output: [{
name: "Promise",
type: "SignInRes",
children: [{
name: "data",
type: "SignInResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "用户详细信息，包含身份信息和元数据",
},
{
name: "session",
type: "Session",
required: true,
description: "会话信息，包含访问令牌和刷新令牌",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]}]
}}
> 
<Tabs>
<TabItem value="1" label="微信令牌登录" default>

```typescript
const { data, error } = await auth.signInWithIdToken({
  provider: "wechat",
  token: "wx_token_1234567890",
});

if (error) {
  console.error("微信登录失败:", error.message);
} else {
  console.log("微信登录成功，用户信息:", data.user);
  console.log("会话信息:", data.session);
}
```

</TabItem>

<TabItem value="2" label="Google令牌登录" default>

```typescript
const { data, error } = await auth.signInWithIdToken({
  provider: "google",
  token: "google_token_abcdefg",
});

if (error) {
  console.error("Google登录失败:", error.message);
} else {
  console.log("Google登录成功，用户昵称:", data.user?.user_metadata?.nickName);
}
```

</TabItem>

<TabItem value="3" label="通用令牌登录" default>

```typescript
const { data, error } = await auth.signInWithIdToken({
  token: "generic_token_xyz",
});

if (error) {
  console.error("令牌登录失败:", error.message);
} else {
  console.log("令牌登录成功，用户ID:", data.user?.id);
}
```

</TabItem>

<TabItem value="4" label="错误处理" default>

```typescript
try {
  const { data, error } = await auth.signInWithIdToken({
    provider: "wechat",
    token: "invalid_token",
  });

  if (error) {
    switch (error.code) {
      case "invalid_token":
        console.error("令牌无效或已过期，请重新获取");
        break;
      case "provider_not_supported":
        console.error("不支持的第三方平台，请使用其他登录方式");
        break;
      case "failed_precondition":
        console.error("从第三方获取用户信息失败，请重试");
        break;
      case "resource_exhausted":
        console.error("尝试过于频繁，请稍后重试");
        break;
      case "permission_denied":
        console.error("权限不足，请检查令牌权限范围");
        break;
      case "unreachable":
        console.error("网络连接失败，请检查网络设置后重试");
        break;
      default:
        console.error("登录失败:", error.message);
    }
  } else {
    console.log("登录成功");
  }
} catch (error) {
  console.error("网络错误:", error);
}
```

</TabItem>

</Tabs>
</ApiIntro>

## signInWithCustomTicket

```typescript
async signInWithCustomTicket(getTickFn: GetCustomSignTicketFn): Promise<SignInRes>
```

使用自定义登录票据进行登录，支持完全自定义的登录流程。

- 使用自定义的登录票据进行身份验证，登录票据创建可以在服务端使用[创建自定义登录票据 API](#createticket)
- 支持传入获取自定义登录票据的函数
- 适用于需要完全自定义登录流程的场景
- 签发 Ticket 详细流程可参考[自定义登录](../../../authentication-v2/method/custom-login)

<ApiIntro parameter={{
input: [{
name: "getTickFn",
type: "GetCustomSignTicketFn",
description: "获取自定义登录票据的函数，返回 Promise<string>"
}],
output: [{
name: "Promise",
type: "SignInRes",
children: [{
name: "data",
type: "SignInResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "用户详细信息，包含身份信息和元数据",
},
{
name: "session",
type: "Session",
required: true,
description: "会话信息，包含访问令牌和刷新令牌",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]}]
}}
> 
<Tabs>
<TabItem value="1" label="基本用法" default>

```typescript
// 获取自定义登录票据的函数
const getTickFn = () => Promise.resolve("custom_ticket_123456");

const { data, error } = await auth.signInWithCustomTicket(getTickFn);

if (error) {
  console.error("自定义登录失败:", error.message);
} else {
  console.log("自定义登录成功，用户信息:", data.user);
  console.log("会话信息:", data.session);
}
```

</TabItem>

<TabItem value="2" label="异步获取票据" default>

```typescript
// 异步获取自定义登录票据
const getTickFn = async () => {
  // 模拟从后端API获取票据
  const response = await fetch("/api/get-custom-ticket");
  const data = await response.json();
  return data.ticket;
};

const { data, error } = await auth.signInWithCustomTicket(getTickFn);

if (error) {
  console.error("自定义登录失败:", error.message);
} else {
  console.log("自定义登录成功");
}
```

</TabItem>

<TabItem value="3" label="错误处理" default>

```typescript
try {
  const getTickFn = () => Promise.resolve("custom_ticket_123456");
  const { data, error } = await auth.signInWithCustomTicket(getTickFn);

  if (error) {
    switch (error.code) {
      case "invalid_ticket":
        console.error("票据无效或已过期，请重新获取");
        break;
      case "ticket_required":
        console.error("需要提供自定义登录票据");
        break;
      case "unreachable":
        console.error("网络连接失败，请检查网络设置后重试");
        break;
      default:
        console.error("登录失败:", error.message);
    }
  } else {
    console.log("登录成功");
  }
} catch (error) {
  console.error("网络错误:", error);
}
```

</TabItem>

</Tabs>
</ApiIntro>

## signInWithOpenId

```typescript
async signInWithOpenId(params?: SignInWithOpenIdReq): Promise<SignInRes>
```

微信小程序 OpenID 静默登录。如果用户不存在，会根据[云开发平台/登录方式](https://tcb.cloud.tencent.com/dev?envId=#/identity/login-manage)中对应身份源的`登录模式`配置，判断是否自动注册。

:::info 提示
仅支持在 `微信小程序` 中使用
:::

<ApiIntro parameter={{
input: [{
name: "params",
type: "SignInWithOpenIdReq",
description: "登录参数",
children: [{
name: "useWxCloud",
type: "boolean",
required: false,
defaultValue: "true",
description: "默认值为true，true：使用微信云开发模式进行请求，需创建小程序微信云开发环境；false：使用普通 http 请求"
}]
}],
output: [{
name: "Promise",
type: "SignInRes",
children: [{
name: "data",
type: "SignInResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "用户详细信息，包含身份信息和元数据，未登录时为 undefined",
},
{
name: "session",
type: "Session",
required: true,
description: "会话信息，包含访问令牌和刷新令牌，未登录时为 undefined",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="微信云开发模式">

```js
const { data, error } = await auth.signInWithOpenId();
```

</TabItem>

<TabItem value="2" label="普通 http 模式">

```js
const { data, error } = await auth.signInWithOpenId({ useWxCloud: false });
```

</TabItem>
</Tabs>
</ApiIntro>

## signInWithPhoneAuth

```typescript
async signInWithPhoneAuth(params: SignInWithPhoneAuthReq): Promise<SignInRes>
```

微信小程序手机号授权登录。如果用户不存在，会根据[云开发平台/登录方式](https://tcb.cloud.tencent.com/dev?envId=#/identity/login-manage)中对应身份源的`登录模式`配置，判断是否自动注册。

:::info 提示
仅支持在 `微信小程序` 中使用
:::

<ApiIntro parameter={{
input: [{
name: "params",
type: "SignInWithPhoneAuthReq",
required: true,
description: "登录参数",
children: [{
name: "phoneCode",
type: "string",
required: true,
description: "微信小程序手机号授权码，通过微信小程序手机号快速验证组件获取"
}]
}],
output: [{
name: "Promise",
type: "SignInRes",
children: [{
name: "data",
type: "SignInResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "用户详细信息，包含身份信息和元数据，未登录时为 undefined",
},
{
name: "session",
type: "Session",
required: true,
description: "会话信息，包含访问令牌和刷新令牌，未登录时为 undefined",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="基本用法">

```js
const { data, error } = await auth.signInWithPhoneAuth({ phoneCode: "xxx" });
```

</TabItem>
</Tabs>
</ApiIntro>

## 会话管理

## getSession

```typescript
async getSession(): Promise<SignInRes>
```

获取当前会话信息，检查用户登录状态。

- 获取当前用户的会话信息，包括访问令牌、用户信息等
- 检查用户是否已登录，未登录时返回空会话

<ApiIntro parameter={{
input: [],
output: [{
name: "Promise",
type: "SignInRes",
children: [{
name: "data",
type: "SignInResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "用户详细信息，包含身份信息和元数据，未登录时为 undefined",
},
{
name: "session",
type: "Session",
required: true,
description: "会话信息，包含访问令牌和刷新令牌，未登录时为 undefined",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="检查用户登录状态" default>

```typescript
const { data, error } = await auth.getSession();

if (error) {
  console.error("获取会话失败:", error.message);
} else if (data.session) {
  console.log("用户已登录:", data.session.user);
  console.log("访问令牌:", data.session.access_token);
  console.log("过期时间:", data.session.expires_in, "秒");
} else {
  console.log("用户未登录，请先登录");
  // 显示登录按钮
  document.getElementById("loginBtn").style.display = "block";
}
```

</TabItem>

<TabItem value="2" label="页面加载时检查登录状态" default>

```typescript
document.addEventListener("DOMContentLoaded", async () => {
  const { data, error } = await auth.getSession();

  if (error) {
    console.error("检查登录状态失败:", error.message);
    return;
  }

  if (data.session) {
    // 用户已登录，显示用户信息
    document.getElementById("userInfo").innerHTML = `
      <p>欢迎，${data.session.user?.name || data.session.user?.username}</p>
    `;
    document.getElementById("loginBtn").style.display = "none";
    document.getElementById("logoutBtn").style.display = "block";
  } else {
    // 用户未登录，显示登录界面
    document.getElementById("loginForm").style.display = "block";
  }
});
```

</TabItem>

<TabItem value="3" label="定时检查会话状态" default>

```typescript
// 定时检查会话状态，自动刷新令牌
function setupSessionMonitor() {
  setInterval(async () => {
    const { data, error } = await auth.getSession();

    if (error) {
      console.error("会话检查失败:", error.message);
    } else if (data.session) {
      const expiresIn = data.session.expires_in;

      // 如果令牌将在5分钟内过期，则自动刷新
      if (expiresIn < 300) {
        console.log("令牌即将过期，自动刷新...");
        await auth.refreshSession();
      }
    }
  }, 60000); // 每分钟检查一次
}

// 启动会话监控
setupSessionMonitor();
```

</TabItem>

<TabItem value="4" label="错误处理" default>

```typescript
try {
  const { data, error } = await auth.getSession();

  if (error) {
    switch (error.code) {
      case "unreachable":
        console.error("网络连接失败，请检查网络设置后重试");
        break;
      case "token_expired":
        console.error("访问令牌已过期，请重新登录");
        // 自动刷新令牌
        await auth.refreshSession();
        break;
      case "invalid_refresh_token":
        console.error("刷新令牌无效，请重新登录");
        break;
      case "refresh_token_expired":
        console.error("刷新令牌已过期，请重新登录");
        break;
      case "user_not_found":
        console.error("用户不存在，请重新登录");
        break;
      case "permission_denied":
        console.error("权限不足，请检查安全域名配置");
        break;
      default:
        console.error("获取会话失败:", error.message);
    }
  } else {
    console.log("会话获取成功");
  }
} catch (error) {
  console.error("未知错误:", error);
}
```

</TabItem>

</Tabs>
</ApiIntro>

---

## refreshSession

```typescript
async refreshSession(refresh_token?: string): Promise<SignInRes>
```

刷新会话令牌，延长用户登录状态，支持自动续期和错误恢复。

- 使用刷新令牌获取新的访问令牌
- 延长用户会话的有效期
- 支持使用指定的刷新令牌或默认令牌

<ApiIntro parameter={{
input: [
{
name: "refresh_token",
type: "string",
children: [{
name: "refresh_token",
type: "string",
required: true,
description: "刷新令牌，默认使用当前会话的刷新令牌，支持自定义令牌",
}]
}
],
output: [{
name: "Promise",
type: "SignInRes",
children: [{
name: "data",
type: "SignInResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "用户详细信息，包含身份信息和元数据",
},
{
name: "session",
type: "Session",
required: true,
description: "新的会话信息，包含更新后的访问令牌和刷新令牌",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="自动刷新会话" default>

```typescript
const { data, error } = await auth.refreshSession();

if (error) {
  console.error("刷新会话失败:", error.message);
  // 刷新失败，可能需要重新登录
  window.location.href = "/login";
} else {
  console.log("会话刷新成功，新令牌:", data.session?.access_token);
  console.log("新过期时间:", data.session?.expires_in, "秒");
}
```

</TabItem>

<TabItem value="2" label="自定义刷新令牌" default>

```typescript
const savedRefreshToken = "refresh_token";

if (savedRefreshToken) {
  const { data, error } = await auth.refreshSession(savedRefreshToken);

  if (error) {
    console.error("使用保存的令牌刷新失败:", error.message);
  } else {
    console.log("使用保存的令牌刷新成功");
  }
} else {
  console.log("没有保存的刷新令牌，使用默认方式刷新");
  const { data, error } = await auth.refreshSession();

  if (error) {
    console.error("刷新失败:", error.message);
  }
}
```

</TabItem>

<TabItem value="3" label="定时自动刷新" default>

```typescript
// 设置定时器，在令牌过期前自动刷新
function setupTokenRefresh() {
  setInterval(async () => {
    const { data, error } = await auth.getSession();

    if (data.session) {
      const expiresIn = data.session.expires_in;

      // 如果令牌将在5分钟内过期，则刷新
      if (expiresIn < 300) {
        console.log("令牌即将过期，自动刷新...");
        const { data: refreshData, error: refreshError } =
          await auth.refreshSession();

        if (refreshError) {
          console.error("自动刷新失败:", refreshError.message);
        } else {
          console.log("自动刷新成功");
        }
      }
    }
  }, 60000); // 每分钟检查一次
}

// 启动定时刷新
setupTokenRefresh();
```

</TabItem>

<TabItem value="4" label="错误处理" default>

```typescript
try {
  const { data, error } = await auth.refreshSession();

  if (error) {
    switch (error.code) {
      case "invalid_refresh_token":
        console.error("刷新令牌无效，请重新登录");
        // 需要重新登录
        window.location.href = "/login";
        break;
      case "refresh_token_expired":
        console.error("刷新令牌已过期，请重新登录");
        // 需要重新登录
        window.location.href = "/login";
        break;
      case "user_not_found":
        console.error("用户不存在，请重新注册");
        // 清除本地会话
        localStorage.removeItem("refresh_token");
        break;
      case "unreachable":
        console.error("网络连接失败，请检查网络设置后重试");
        break;
      case "permission_denied":
        console.error("权限不足，请检查安全域名配置");
        break;
      case "resource_exhausted":
        console.error("刷新频率过高，请稍后重试");
        break;
      default:
        console.error("刷新失败:", error.message);
    }
  } else {
    console.log("刷新成功");
  }
} catch (error) {
  console.error("网络错误:", error);
}
```

</TabItem>

</Tabs>
</ApiIntro>

---

## setSession

```typescript
async setSession(params: SetSessionReq): Promise<SignInRes>
```

使用现有的访问令牌和刷新令牌来设置用户会话，支持外部系统集成和手动会话管理。

- 使用现有的 access_token 和 refresh_token 来设置用户会话
- 适用于从外部系统获取令牌后手动设置会话的场景
- 成功设置会话后会触发 SIGNED_IN 事件

<ApiIntro parameter={{
input: [
{
name: "params",
type: "SetSessionReq",
children: [
{
name: "access_token",
type: "string",
description: "访问令牌，用于 API 调用认证和用户身份验证",
},
{
name: "refresh_token",
type: "string",
required: true,
description: "刷新令牌，用于获取新的访问令牌，延长会话有效期",
},
]
}
],
output: [{
name: "Promise",
type: "SignInRes",
children: [{
name: "data",
type: "SignInResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "用户详细信息，包含身份信息和元数据",
},
{
name: "session",
type: "Session",
required: true,
description: "会话信息，包含访问令牌和刷新令牌",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="基础会话设置" default>

```typescript
const { data, error } = await auth.setSession({
  access_token: "your_access_token_here",
  refresh_token: "your_refresh_token_here",
});

if (error) {
  console.error("会话设置失败:", error.message);
} else {
  console.log("会话设置成功");
  console.log("用户信息:", data.user);
  console.log("会话信息:", data.session);
}
```

</TabItem>

</Tabs>
</ApiIntro>

---

## signOut

```typescript
async signOut(params?: SignOutReq): Promise<SignOutRes>
```

用户登出，清除当前会话和本地存储。

- 安全退出当前用户登录状态
- 清除服务器端会话和本地存储
- 支持重定向到指定页面
- 触发认证状态变化事件

<ApiIntro parameter={{
input: [
{
name: "params",
type: "SignOutReq",
children: [{
name: "options",
type: "SignOutReqOptions",
description: "登出配置选项",
children: [
{
name: "redirectTo",
type: "string",
description: "登出后的重定向地址，支持相对路径和绝对 URL",
},
{
name: "clearStorage",
type: "boolean",
description: "是否清除本地存储，默认 true，设为 false 可保留用户偏好",
},
],
},]
}
],
output: [{
name: "Promise",
type: "SignOutRes",
children: [{
name: "data",
type: "object",
required: true,
description: "空对象，无特殊意义",
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="基础登出操作" default>

```typescript
const { data, error } = await auth.signOut();

if (error) {
  console.error("登出失败:", error.message);
} else {
  console.log("登出成功");
  // 登出后跳转到登录页
  window.location.href = "/login";
}
```

</TabItem>

<TabItem value="2" label="登出并重定向" default>

```typescript
const { data, error } = await auth.signOut({
  options: {
    redirectTo: "/login",
    clearStorage: true,
  },
});

if (error) {
  console.error("登出失败:", error.message);
} else {
  console.log("登出成功，正在跳转到登录页...");
  // 自动重定向到登录页
  window.location.href = "/login";
}
```

</TabItem>

<TabItem value="3" label="安全登出流程" default>

```typescript
async function safeSignOut() {
  // 显示确认对话框
  if (!confirm("确定要退出登录吗？")) {
    return;
  }

  // 显示加载状态
  document.getElementById("logoutBtn").disabled = true;
  document.getElementById("logoutBtn").innerText = "登出中...";

  const { data, error } = await auth.signOut();

  if (error) {
    console.error("登出失败:", error.message);
    alert("登出失败: " + error.message);

    // 恢复按钮状态
    document.getElementById("logoutBtn").disabled = false;
    document.getElementById("logoutBtn").innerText = "退出登录";
  } else {
    console.log("登出成功");

    // 清除本地存储
    localStorage.removeItem("user_session");
    sessionStorage.clear();

    // 显示成功消息
    alert("已安全退出登录");

    // 跳转到登录页
    window.location.href = "/login";
  }
}

// 登出按钮点击事件
document.getElementById("logoutBtn").addEventListener("click", safeSignOut);
```

</TabItem>

<TabItem value="4" label="错误处理" default>

```typescript
try {
  const { data, error } = await auth.signOut();

  if (error) {
    switch (error.code) {
      case "unreachable":
        console.error("网络连接失败，请检查网络设置后重试");
        alert("网络连接失败，请稍后重试");
        break;
      case "session_not_found":
        console.error("会话不存在，可能已经登出");
        // 清除本地存储并跳转
        localStorage.clear();
        window.location.href = "/login";
        break;
      case "token_invalid":
        console.error("令牌无效，请重新登录");
        // 强制清除并跳转
        localStorage.clear();
        window.location.href = "/login";
        break;
      case "permission_denied":
        console.error("权限不足，无法执行登出操作");
        alert("权限不足，无法登出");
        break;
      case "unreachable":
        console.error("服务器连接失败，请检查网络设置");
        alert("服务器连接失败，请检查网络");
        break;
      default:
        console.error("登出失败:", error.message);
        alert("登出失败: " + error.message);
    }
  } else {
    console.log("登出成功");

    // 显示成功消息
    alert("已安全退出登录");

    // 跳转到登录页
    window.location.href = "/login";
  }
} catch (error) {
  console.error("未知错误:", error);
  alert("发生未知错误，请重试");
}
```

</TabItem>

</Tabs>
</ApiIntro>

## 用户管理

## getUser

```typescript
async getUser(): Promise<GetUserRes>
```

获取当前登录用户的详细信息，包括身份信息、元数据和权限状态，支持用户资料展示和权限验证。

- 获取当前登录用户的完整信息
- 包括用户基本信息、元数据、身份信息等
  需要用户已登录状态才能获取完整信息
- 支持检查用户权限和验证状态

<ApiIntro parameter={{
input: [],
output: [{
name: "Promise",
type: "GetUserRes",
children: [{
name: "data",
type: "GetUserResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "用户详细信息，包含身份信息、元数据和权限状态",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="基础用户信息获取" default>

```typescript
const { data, error } = await auth.getUser();

if (error) {
  console.error("获取用户信息失败:", error.message);
} else if (data.user) {
  const user = data.user;
  console.log("用户ID:", user.id);
  console.log("邮箱:", user.email);
  console.log("手机号:", user.phone);
  console.log("用户名:", user.user_metadata?.username);
  console.log("昵称:", user.user_metadata?.nickName);
  console.log("头像:", user.user_metadata?.avatarUrl);
  console.log("注册时间:", user.created_at);
} else {
  console.log("用户未登录");
}
```

</TabItem>

<TabItem value="2" label="用户资料页面实现" default>

```typescript
// 在用户资料页面显示详细信息
async function loadUserProfile() {
  const { data, error } = await auth.getUser();

  if (error) {
    console.error("获取用户信息失败:", error.code, error.category, error.message);
    return;
  }

  if (data.user) {
    const user = data.user;
    console.log("用户邮箱:", user.email || "未设置");
    console.log("用户手机:", user.phone || "未设置");
    console.log("用户名:", user.user_metadata?.name || "未设置");
    console.log("昵称:", user.user_metadata?.nickName || "未设置");
    console.log("注册时间:", new Date(user.created_at).toLocaleString());
  } else {
    console.error("用户未登录");
  }
}

// 页面加载时调用
loadUserProfile();
```

</TabItem>

<TabItem value="3" label="检查用户权限" default>

```typescript
async function checkUserPermissions() {
  const { data, error } = await auth.getUser();

  if (error) {
    console.error("获取用户信息失败:", error.message);
    return false;
  }

  if (data.user) {
    const user = data.user;

    // 检查邮箱是否已验证
    if (!user.email_confirmed_at) {
      console.log("邮箱未验证，需要验证邮箱");
      return false;
    }

    // 检查用户角色
    if (user.role?.includes("administrator")) {
      console.log("管理员用户，拥有全部权限");
      return true;
    } else if (!!user.role?.length) {
      console.log("普通用户，拥有基本权限");
      return true;
    } else {
      console.log("未知用户角色");
      return false;
    }
  } else {
    console.log("用户未登录，无权限");
    return false;
  }
}

// 检查权限并执行操作
if (await checkUserPermissions()) {
  // 有权限，执行操作
  console.log("有权限，继续执行...");
} else {
  // 无权限，显示错误
  console.log("无权限，操作被拒绝");
}
```

</TabItem>

<TabItem value="4" label="错误处理" default>

```typescript
try {
  const { data, error } = await auth.getUser();

  if (error) {
    switch (error.code) {
      case "user_not_found":
        console.error("用户不存在，请重新登录");
        // 可能是会话已过期，需要重新登录
        window.location.href = "/login";
        break;
      case "token_expired":
        console.error("访问令牌已过期，尝试刷新令牌");
        // 尝试刷新令牌
        await auth.refreshSession();
        // 重新获取用户信息
        await auth.getUser();
        break;
      case "unreachable":
        console.error("网络连接失败，请检查网络设置后重试");
        break;
      case "permission_denied":
        console.error("权限不足，请检查安全域名配置");
        break;
      case "invalid_refresh_token":
        console.error("刷新令牌无效，请重新登录");
        window.location.href = "/login";
        break;
      case "refresh_token_expired":
        console.error("刷新令牌已过期，请重新登录");
        window.location.href = "/login";
        break;
      default:
        console.error("获取用户信息失败:", error.message);
    }
  } else {
    console.log("用户信息获取成功");
  }
} catch (error) {
  console.error("未知错误:", error);
}
```

</TabItem>

</Tabs>
</ApiIntro>

---

## refreshUser

```typescript
async refreshUser(): Promise<CommonRes>
```

刷新当前登录用户的信息。

- 刷新当前登录用户的完整信息
- 从服务器重新获取最新的用户数据
- 适用于用户信息可能已更新但本地缓存未同步的场景
  需要用户已登录状态才能刷新信息

<ApiIntro parameter={{
input: [],
output: [{
name: "Promise",
type: "CommonRes",
children: [{
name: "data",
type: "CommonResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "刷新后的用户信息",
},
{
name: "session",
type: "Session",
required: true,
description: "刷新后的会话信息",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="基础刷新" default>

```typescript
const { data, error } = await auth.refreshUser();

if (error) {
  console.error("刷新用户信息失败:", error.message);
} else {
  console.log("用户信息已刷新");
  console.log("最新用户信息:", data.user);
  console.log("最新会话信息:", data.session);
}
```

</TabItem>

<TabItem value="2" label="用户资料页面刷新" default>

```typescript
// 当用户修改资料后，刷新页面显示
async function refreshUserProfile() {
  const { data, error } = await auth.refreshUser();

  if (error) {
    console.error("刷新失败:", error.message);
    return false;
  }

  if (data.user) {
    const user = data.user;

    // 更新页面显示
    document.getElementById("userEmail").innerText = user.email || "未设置";
    document.getElementById("userPhone").innerText = user.phone || "未设置";
    document.getElementById("name").innerText =
      user.user_metadata?.name || "未设置";
    document.getElementById("userNickname").innerText =
      user.user_metadata?.nickName || "未设置";
    document.getElementById("userAvatar").src =
      user.user_metadata?.avatarUrl || "/default-avatar.png";

    console.log("用户信息已刷新并更新显示");
    return true;
  }

  return false;
}

// 在用户修改资料后调用
await refreshUserProfile();
```

</TabItem>

<TabItem value="3" label="错误处理" default>

```typescript
async function safeRefreshUser() {
  try {
    const { data, error } = await auth.refreshUser();

    if (error) {
      switch (error.code) {
        case "user_not_found":
          console.error("用户不存在，请重新登录");
          break;
        case "token_expired":
          console.error("访问令牌已过期，尝试刷新会话");
          await auth.refreshSession();
          // 重新刷新用户信息
          return await auth.refreshUser();
        case "unreachable":
          console.error("网络连接失败，请检查网络设置后重试");
          break;
        default:
          console.error("刷新用户信息失败:", error.message);
      }
      return null;
    }

    return data;
  } catch (error) {
    console.error("刷新过程中发生未知错误:", error);
    return null;
  }
}

// 安全地刷新用户信息
const refreshedData = await safeRefreshUser();
if (refreshedData) {
  console.log("用户信息刷新成功");
}
```

</TabItem>

</Tabs>
</ApiIntro>

---

## updateUser

```typescript
async updateUser(params: UserAttributes): Promise<UserResponse | UpdateUserWithVerificationRes>
```

更新当前登录用户的信息。

- **不支持更新密码**：`updateUser` 不接受 `password` / `new_password` 参数，传入将直接抛出错误。更新密码请使用 [resetPasswordForOld](#resetPasswordForOld)（旧密码修改）、[resetPasswordForEmail](#resetpasswordforemail)（验证码重置）或 [reauthenticate](#reauthenticate)（重新认证后改密）
- 更新当前登录用户的基本信息和元数据
- 支持更新邮箱、手机号、用户名、昵称、头像等
- 需要用户已登录状态才能更新信息
  更新成功后返回更新后的用户信息

:::warning 不支持修改密码
`updateUser` 仅用于更新用户基本资料，**不支持修改密码**。若传入 `password` 或 `new_password` 参数，将抛出错误：

```
updateUser 不支持更新密码，检测到传入了 "password" 参数。如需修改密码请使用 resetPasswordForOld（旧密码修改）、resetPasswordForEmail（验证码重置）或 reauthenticate（重新认证后改密）
```

请根据场景改用对应的密码更新接口：

- [resetPasswordForOld](#resetPasswordForOld)：已知旧密码时直接修改
- [resetPasswordForEmail](#resetpasswordforemail)：通过邮箱验证码重置
- [reauthenticate](#reauthenticate)：重新认证后修改
:::

<ApiIntro parameter={{
input: [
{
name: "params",
type: "UserAttributes",
children: [
{
name: "email",
type: "string",
description: "邮箱地址",
},
{
name: "phone",
type: "string",
description: "手机号码",
},
{
name: "username",
type: "string",
description: "用户名称，长度 5-24 位，支持英文大小写、数字、特殊字符（仅支持-_.:+ @），且只能以字母或数字开头，不支持中文",
},
{
name: "description",
type: "string",
description: "用户描述信息",
},
{
name: "avatar_url",
type: "string",
description: "头像 URL 地址",
},
{
name: "nickname",
type: "string",
description: "用户昵称",
},
{
name: "gender",
type: "'MALE' | 'FEMALE'",
description: "用户性别",
},
]
}
],
output: [{
name: "Promise",
type: "GetUserRes",
children: [{
name: "data",
type: "GetUserResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "更新后的用户详细信息",
},
{
name: "verifyOtp",
type: "(params: verifyParams) => Promise<SignInRes>",
description: "验证码回调函数，修改手机号或邮箱时需要验证码",
children: [{
name: "params",
type: "verifyParams",
required: true,
description: "状态变化回调函数入参",
children: [
{
name: "token",
type: "string",
required: true,
description: "验证码",
},
{
name: "email",
type: "string",
description: "邮箱",
},
{
name: "phone",
type: "string",
description: "手机号",
}
]
},
{
name: "return",
type: "Promise<SignInRes>",
required: true,
description: "返回",children: [{
name: "data",
type: "SignInResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "用户详细信息，包含身份信息和元数据",
},
]
},{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
},
]
}
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="基本信息更新" default>

```typescript
const { data, error } = await auth.updateUser({
  nickname: "新昵称",
  gender: "MALE",
});

if (error) {
  console.error("更新用户信息失败:", error.message);
} else {
  console.log("用户信息已更新:", data.user);
  console.log("新邮箱:", data.user?.email);
  console.log("新昵称:", data.user?.user_metadata?.nickName);
}
```

</TabItem>

<TabItem value="2" label="邮箱/手机号更新" default>

```typescript
// 更新 email 或 phone（需要验证）
const { data } = await app.auth.updateUser({
  email: "new@example.com",
});

// 调用 verifyOtp 回调验证
await data.verifyOtp({ email: "new@example.com", token: "123456" });
```

</TabItem>

<TabItem value="3" label="用户资料编辑页面" default>

```typescript
async function saveUserProfile(formData) {
  const { data, error } = await auth.updateUser({
    username: formData.username,
    nickname: formData.nickname,
    gender: formData.gender,
    description: formData.description,
    avatar_url: formData.avatarUrl,
  });

  if (error) {
    console.error("保存失败:", error.code, error.category, error.message);
    return false;
  } else {
    console.log("资料保存成功");
    return true;
  }
}

// 调用示例
await saveUserProfile({
  username: "new_username",
  nickname: "新昵称",
  gender: "male",
  description: "个人简介",
  avatarUrl: "https://example.com/avatar.png",
});
```

</TabItem>

<TabItem value="4" label="错误处理" default>

```typescript
try {
  // 第一步：更新用户信息（发送验证码阶段）
  const { data, error } = await auth.updateUser({
    email: "new@example.com",
  });

  if (error) {
    console.error("更新失败:", error.code, error.category, error.message);
    switch (error.code) {
      case "invalid_argument":
        console.error("参数格式错误:", error.message);
        break;
      case "failed_precondition":
        console.error("前置条件不满足:", error.message);
        break;
      case "resource_exhausted":
        console.error("发送频率过高，请稍后再试");
        break;
      case "unreachable":
        console.error("网络连接失败，请检查网络设置后重试");
        break;
      default:
        console.error("更新失败:", error.message);
    }
    return;
  }

  // 第二步：如果修改了邮箱/手机号，需要验证码验证（verify 阶段）
  if (data.verifyOtp) {
    const { data: verifyData, error: verifyError } = await data.verifyOtp({
      email: "new@example.com",
      token: "123456",
    });

    if (verifyError) {
      console.error("验证失败:", verifyError.code, verifyError.category, verifyError.message);
      switch (verifyError.code) {
        case "invalid_argument":
          // 验证码过期/不正确
          console.error(
            verifyError.message || "验证码已过期或不正确，请重新获取"
          );
          break;
        case "unauthenticated":
          // Token 失效，需要重新登录
          console.error("认证失效，请重新登录");
          window.location.href = "/login";
          break;
        case "failed_precondition":
          // 该邮箱/手机号已被其他账号绑定
          console.error(verifyError.message);
          break;
        case "not_found":
          console.error("用户不存在，请重新登录");
          break;
        case "unavailable":
          console.error("服务暂不可用，请稍后再试");
          break;
        default:
          console.error("验证失败:", verifyError.message);
      }
    } else {
      console.log("邮箱更新成功");
    }
  } else {
    console.log("用户信息更新成功");
  }
} catch (error) {
  console.error("网络错误:", error);
}
```

</TabItem>

</Tabs>
</ApiIntro>

---

## deleteUser

```typescript
async deleteUser(params: DeleteMeReq): Promise<CommonRes>
```

删除当前登录用户的账户。

- 永久删除当前登录用户的账户
- 需要验证用户密码进行身份确认
- 删除后所有用户数据将被永久移除
- 操作不可逆，请谨慎使用

<ApiIntro parameter={{
input: [
{
name: "params",
type: "DeleteMeReq",
children: [
{
name: "password",
type: "string",
required: true,
description: "用户密码，用于身份验证",
},
]
}
],
output: [{
name: "Promise",
type: "CommonRes",
children: [{
name: "data",
type: "CommonResData",
required: true,
description: "",
children: [
{
name: "空对象",
type: "object",
required: true,
description: "无特殊意义",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="基础账户删除" default>

```typescript
const { data, error } = await auth.deleteUser({
  password: "userPassword123",
});

if (error) {
  console.error("账户删除失败:", error.message);
} else {
  console.log("账户删除成功");
  // 用户已登出，重定向到首页
  window.location.href = "/";
}
```

</TabItem>

<TabItem value="2" label="账户删除确认页面" default>

```typescript
async function deleteAccount(password) {
  if (!confirm("确定要删除账户吗？此操作不可逆，所有数据将被永久删除！")) {
    return false;
  }

  const { data, error } = await auth.deleteUser({ password });

  if (error) {
    switch (error.code) {
      case "invalid_password":
        alert("密码错误，请重新输入");
        break;
      case "user_not_found":
        alert("用户不存在");
        break;
      default:
        alert("删除失败: " + error.message);
    }
    return false;
  } else {
    alert("账户删除成功");
    return true;
  }
}

// 删除账户表单提交
document
  .getElementById("deleteAccountForm")
  .addEventListener("submit", async (e) => {
    e.preventDefault();

    const password = document.getElementById("password").value;
    const success = await deleteAccount(password);

    if (success) {
      // 重定向到首页
      window.location.href = "/";
    }
  });
```

</TabItem>

<TabItem value="3" label="两步验证删除" default>

```typescript
async function deleteAccountWithVerification(password, verificationCode) {
  // 第一步：验证密码
  const { data: verifyData, error: verifyError } = await auth.reauthenticate();

  if (verifyError) {
    alert("身份验证失败: " + verifyError.message);
    return false;
  }

  // 第二步：等待验证码输入
  const { data: updateData, error: updateError } = await verifyData.updateUser({
    nonce: verificationCode,
    password,
  });

  if (updateError) {
    alert("验证码错误: " + updateError.message);
    return false;
  }

  // 第三步：删除账户
  const { data, error } = await auth.deleteUser({ password });

  if (error) {
    alert("删除失败: " + error.message);
    return false;
  } else {
    alert("账户删除成功");
    return true;
  }
}
```

</TabItem>

<TabItem value="4" label="安全删除流程" default>

```typescript
class AccountDeletionManager {
  constructor() {
    this.deletionAttempts = 0;
    this.maxAttempts = 3;
  }

  async deleteAccount(password) {
    if (this.deletionAttempts >= this.maxAttempts) {
      alert("删除尝试次数过多，请稍后再试");
      return false;
    }

    this.deletionAttempts++;

    const { data, error } = await auth.deleteUser({ password });

    if (error) {
      if (error.code === "invalid_password") {
        const remainingAttempts = this.maxAttempts - this.deletionAttempts;
        alert(`密码错误，剩余尝试次数: ${remainingAttempts}`);
      } else {
        alert("删除失败: " + error.message);
      }
      return false;
    } else {
      alert("账户删除成功");
      this.deletionAttempts = 0;
      return true;
    }
  }

  resetAttempts() {
    this.deletionAttempts = 0;
  }
}

// 使用账户删除管理器
const deletionManager = new AccountDeletionManager();

// 删除账户
document.getElementById("deleteBtn").addEventListener("click", async () => {
  const password = prompt("请输入密码确认删除账户:");
  if (password) {
    await deletionManager.deleteAccount(password);
  }
});
```

</TabItem>

</Tabs>
</ApiIntro>

## 身份源管理

## getUserIdentities

```typescript
async getUserIdentities(): Promise<GetUserIdentitiesRes>
```

获取当前用户绑定的所有身份源信息。

- 获取所有第三方身份源，相关身份源可在[云开发平台/身份认证/登录方式](https://tcb.cloud.tencent.com/dev?envId=#/identity/login-manage)中进行配置配置
- 返回身份源的详细信息，包括平台标识、身份源 ID、绑定时间等
- 需要用户已登录状态才能获取身份源信息

<ApiIntro parameter={{
input: [],
output: [{
name: "Promise",
type: "GetUserIdentitiesRes",
children: [{
name: "data",
type: "GetUserIdentitiesResData",
required: true,
description: "",
children: [
{
name: "identities",
type: "Array<Identity>",
required: true,
description: "身份源信息列表",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="获取用户绑定的身份源" default>

```typescript
const { data, error } = await auth.getUserIdentities();

if (error) {
  console.error("获取身份源失败:", error.message);
} else if (data.identities) {
  console.log("用户绑定的身份源:", data.identities);

  data.identities.forEach((identity) => {
    console.log(
      `- ${identity.name} (${identity.provider}): ${identity.provider_user_id}`
    );
    console.log(
      `  绑定时间: ${new Date(identity.created_at).toLocaleString()}`
    );
  });
} else {
  console.log("用户未绑定任何身份源");
}
```

</TabItem>

<TabItem value="2" label="显示身份源管理界面" default>

```typescript
async function loadUserIdentities() {
  const { data, error } = await auth.getUserIdentities();

  if (error) {
    console.error("获取身份源失败:", error.code, error.category, error.message);
    return;
  }

  if (data.identities && data.identities.length > 0) {
    data.identities.forEach((identity) => {
      console.log(`身份源: ${identity.name}, 平台: ${identity.provider}, 绑定时间: ${new Date(identity.created_at).toLocaleString()}`);
    });
  } else {
    console.log("您还没有绑定任何第三方账号");
  }
}

// 调用示例
loadUserIdentities();
```

</TabItem>

<TabItem value="3" label="检查是否绑定特定平台" default>

```typescript
async function isProviderBound(provider) {
  const { data, error } = await auth.getUserIdentities();

  if (error) {
    console.error("检查身份源失败:", error.message);
    return false;
  }

  if (data.identities) {
    return data.identities.some((identity) => identity.provider === provider);
  }

  return false;
}

// 检查是否绑定了微信
const isWechatBound = await isProviderBound("wechat");
if (isWechatBound) {
  console.log("已绑定微信账号");
  document.getElementById("bindWechatBtn").style.display = "none";
} else {
  console.log("未绑定微信账号");
  document.getElementById("bindWechatBtn").style.display = "block";
}
```

</TabItem>

</Tabs>
</ApiIntro>

---

## linkIdentity

```typescript
async linkIdentity(params: LinkIdentityReq): Promise<LinkIdentityRes>
```

绑定新的身份源到当前用户，会自动跳转第三方 OAuth 授权页面。

- 将新的第三方身份源绑定到当前登录用户，支持绑定微信、Google、GitHub 等第三方平台，身份源需先在[云开发平台/身份认证/登录方式](https://tcb.cloud.tencent.com/dev?envId=#/identity/login-manage)中进行配置配置
- 绑定成功后，用户可以使用该身份源进行登录
- 需要用户已登录状态才能绑定身份源
- 在 cloudbase.init 时设置`auth.detectSessionInUrl`为 `true` 时，从第三方回调回来后会自动调用 [verifyOAuth](#verifyoauth) 进行验证，否则后续需要手动通过 [verifyOAuth](#verifyoauth) 方法进行验证

<ApiIntro parameter={{
input: [
{
name: "params",
type: "LinkIdentityReq",
children: [{
name: "provider",
type: "string",
required: true,
description: "身份源标识（如：wechat、google、github 等）",
},]
}
],
output: [{
name: "Promise",
type: "LinkIdentityRes",
children: [{
name: "data",
type: "LinkIdentityResData",
required: true,
description: "",
children: [
{
name: "provider",
type: "string",
required: true,
description: "绑定的身份源标识",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="绑定谷歌账号" default>

```typescript
const app = cloudbase.init({
  env: "your-env-id", // 替换为您的环境ID
  region: "ap-shanghai", // 地域，默认为上海
  accessKey: "", // 填入生成的 Publishable Key，
  auth: {
    detectSessionInUrl: true, // 可选：自动检测 URL 中的 OAuth 参数
  },
});

// 监听身份源绑定事件
auth.onAuthStateChange((event, session, info) => {
  console.log("认证状态变化:", { event, session, info });

  switch (event) {
    case "BIND_IDENTITY":
      if (!!info.error) {
        console.error("身份源绑定失败:", info.error);
        // 可以在这里添加UI错误提示
      } else {
        console.log("身份源已绑定");
        // 重新加载身份源列表
        await auth.getUserIdentities();
      }
      break;

    default:
      return;
  }
});

try {
  const { data, error } = await auth.linkIdentity({
    provider: "google",
  });

  if (error) {
    console.error("绑定身份源失败:", error.message);
    // 处理绑定失败逻辑
    return;
  }

  console.log("身份源绑定请求已发送，等待用户授权...");
  // 绑定请求成功，等待用户完成OAuth授权流程
} catch (error) {
  console.error("调用linkIdentity方法时发生错误:", error);
  // 处理网络错误或其他异常
}
```

</TabItem>

<TabItem value="2" label="绑定流程页面" default>

```typescript
const app = cloudbase.init({
  env: "your-env-id", // 替换为您的环境ID
  region: "ap-shanghai", // 地域，默认为上海
  accessKey: "", // 填入生成的 Publishable Key，
  auth: {
    detectSessionInUrl: true, // 可选：自动检测 URL 中的 OAuth 参数
  },
});

const auth = app.auth;

async function bindProvider(provider) {
  try {
    // 显示加载状态
    document.getElementById("bindBtn").disabled = true;
    document.getElementById("status").innerText = "绑定中...";

    const { data, error } = await auth.linkIdentity({ provider });

    if (error) {
      console.error("身份源绑定失败:", error);
      document.getElementById("status").innerText =
        "绑定失败: " + error.message;
      document.getElementById("bindBtn").disabled = false;

      // 根据错误类型提供更具体的提示
      if (error.message.includes("already bound")) {
        document.getElementById("status").innerText =
          "该身份源已绑定，无需重复绑定";
      } else if (error.message.includes("not logged in")) {
        document.getElementById("status").innerText = "请先登录后再绑定身份源";
      } else if (error.message.includes("provider not found")) {
        document.getElementById("status").innerText = "不支持的身份源类型";
      }
    } else {
      console.log("身份源绑定请求已发送，等待用户授权...");
      document.getElementById("status").innerText = "正在跳转授权页面...";

      // 绑定请求成功，等待用户完成OAuth授权流程
      // 实际绑定结果将通过onAuthStateChange事件通知
    }
  } catch (error) {
    console.error("绑定身份源时发生异常:", error);
    document.getElementById("status").innerText = "绑定过程发生异常，请重试";
    document.getElementById("bindBtn").disabled = false;
  }
}

// 监听身份源绑定结果
auth.onAuthStateChange((event, session, info) => {
  if (event === "BIND_IDENTITY") {
    if (info.error) {
      console.error("身份源绑定失败:", info.error);
      document.getElementById("status").innerText =
        "授权失败: " + info.error.message;
      document.getElementById("bindBtn").disabled = false;
    } else {
      console.log("身份源绑定成功");
      document.getElementById("status").innerText = "绑定成功";
      document.getElementById("bindBtn").style.display = "none";

      // 更新身份源列表
      loadUserIdentities();
    }
  }
});

// 绑定按钮点击事件
document.getElementById("bindWechatBtn").addEventListener("click", () => {
  bindProvider("wechat");
});
```

</TabItem>

</Tabs>
</ApiIntro>

---

## unlinkIdentity

```typescript
async unlinkIdentity(params: UnlinkIdentityReq): Promise<CommonRes>
```

解绑当前用户绑定的身份源。

- 解绑当前登录用户绑定的第三方身份源，相关身份源可在[云开发平台/身份认证/登录方式](https://tcb.cloud.tencent.com/dev?envId=#/identity/login-manage)中进行配置配置
- 解绑成功后需要重新加载身份源列表
- 使用身份源标识（provider）而非身份源 ID（identity_id）进行解绑

<ApiIntro parameter={{
input: [
{
name: "params",
type: "UnlinkIdentityReq",
children: [{
name: "provider",
type: "string",
required: true,
description: "身份源标识（如：wechat、google、github 等）",
},]
}
],
output: [{
name: "Promise",
type: "CommonRes",
children: [{
name: "data",
type: "CommonResData",
required: true,
description: "",
children: [
{
name: "空对象",
type: "object",
required: true,
description: "无特殊意义",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="解绑特定身份源" default>

```typescript
const { data, error } = await auth.unlinkIdentity({
  provider: "wechat",
});

if (error) {
  console.error("解绑身份源失败:", error.message);
} else {
  console.log("身份源解绑成功");

  // 重新加载身份源列表
  await auth.getUserIdentities();
}
```

</TabItem>

<TabItem value="2" label="解绑流程页面" default>

```typescript
async function unbindIdentity(provider) {
  if (!confirm("确定要解绑这个账号吗？")) {
    return;
  }

  const { data, error } = await auth.unlinkIdentity({ provider });

  if (error) {
    alert("解绑失败: " + error.message);
  } else {
    alert("解绑成功");

    // 重新加载身份源列表
    await loadUserIdentities();
  }
}

// 解绑按钮点击事件
document.querySelectorAll(".unbind-btn").forEach((btn) => {
  btn.addEventListener("click", (e) => {
    const provider = e.target.dataset.provider;
    unbindIdentity(provider);
  });
});
```

</TabItem>

<TabItem value="3" label="批量解绑" default>

```typescript
async function unbindMultipleProviders(providers) {
  const results = [];

  for (const provider of providers) {
    const result = await auth.unlinkIdentity({ provider });
    results.push({ provider, result });

    if (result.error) {
      console.error(`解绑${provider}失败:`, result.error.message);
    } else {
      console.log(`解绑${provider}成功`);
    }
  }

  return results;
}

// 解绑多个身份源
const providers = ["wechat", "google", "github"];
const unbindResults = await unbindMultipleProviders(providers);

// 统计解绑结果
const successCount = unbindResults.filter((r) => !r.result.error).length;
console.log(
  `成功解绑 ${successCount} 个身份源，失败 ${
    providers.length - successCount
  } 个`
);
```

</TabItem>

<TabItem value="4" label="错误处理" default>

```typescript
try {
  const { data, error } = await auth.unlinkIdentity({
    provider: "invalid_provider",
  });

  if (error) {
    switch (error.code) {
      case "provider_not_found":
        console.error("身份源不存在，请检查身份源标识是否正确");
        break;
      case "last_identity_cannot_unlink":
        console.error("不能解绑最后一个身份源，请至少保留一个登录方式");
        break;
      case "permission_denied":
        console.error("没有权限解绑此身份源，请检查权限设置");
        break;
      case "unreachable":
        console.error("网络连接失败，请检查网络设置后重试");
        break;
      case "resource_exhausted":
        console.error("解绑频率过高，请稍后重试");
        break;
      case "user_not_found":
        console.error("用户不存在，请重新登录");
        break;
      case "token_expired":
        console.error("会话已过期，请重新登录");
        break;
      default:
        console.error("解绑失败:", error.message);
    }
  } else {
    console.log("解绑成功");
  }
} catch (error) {
  console.error("网络错误:", error);
}
```

</TabItem>

</Tabs>
</ApiIntro>

## 密码管理

## resetPasswordForEmail

```typescript
async resetPasswordForEmail(email: string): Promise<ResetPasswordForEmailRes>
```

通过邮箱重置用户密码，采用四步验证流程。

- 通过邮箱发送验证码来重置用户密码
- 采用四步验证流程：发送验证码 → 等待用户输入 → 验证验证码 → 设置新密码
- 需要用户邮箱已注册且已验证

<ApiIntro parameter={{
input: [
{
name: "email",
type: "string",
required: true,
description: "用户注册的邮箱地址",
}
],
output: [{
name: "Promise",
type: "ResetPasswordForEmailRes",
children: [{
name: "data",
type: "ResetPasswordForEmailResData",
required: true,
description: "",
children: [
{
name: "updateUser",
type: "(attributes: UpdateUserAttributes) => Promise<SignInRes>",
required: true,
description: "验证码回调函数，支持新密码参数",
children: [{
name: "attributes",
type: "UpdateUserAttributes",
required: true,
description: "状态变化回调函数入参",
children: [
{
name: "nonce",
type: "string",
required: true,
description: "验证码",
},
{
name: "password",
type: "string",
required: true,
description: "新密码",
}
]
},
{
name: "return",
type: "Promise<SignInRes>",
required: true,
description: "返回",children: [{
name: "data",
type: "SignInResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "用户详细信息，包含身份信息和元数据",
},
{
name: "session",
type: "Session",
required: true,
description: "会话信息，包含访问令牌和刷新令牌",
},
]
},{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="通过邮箱重置密码" default>

```typescript
// 第一步：发送验证码到邮箱
const { data, error } = await auth.resetPasswordForEmail("user@example.com");

if (error) {
  console.error("发送验证码失败:", error.message);
} else {
  console.log("验证码已发送到邮箱，等待用户输入...");

  // 第二步：等待用户输入验证码和新密码
  const verificationCode = "123456"; // 用户输入的验证码
  const newPassword = "newSecurePassword123"; // 用户输入的新密码

  // 第三步：验证验证码并设置新密码
  const { data: loginData, error: loginError } = await data.updateUser({
    nonce: verificationCode,
    password: newPassword,
  });

  if (loginError) {
    console.error("重置密码失败:", loginError.message);
  } else {
    console.log("密码重置成功，用户已自动登录");
    console.log("用户信息:", loginData.user);
  }
}
```

</TabItem>

<TabItem value="2" label="密码重置页面实现" default>

```typescript
let resetPasswordVerify = null;

async function startPasswordReset(email) {
  const { data, error } = await auth.resetPasswordForEmail(email);

  if (error) {
    console.error("发送验证码失败:", error.code, error.category, error.message);
    return false;
  } else {
    resetPasswordVerify = data.updateUser;
    console.log("验证码已发送到您的邮箱，请查收");
    return true;
  }
}

async function completePasswordReset(code, newPassword) {
  if (!resetPasswordVerify) {
    console.error("请先发送验证码");
    return false;
  }

  const { data, error } = await resetPasswordVerify({
    nonce: code,
    password: newPassword,
  });

  if (error) {
    console.error("重置密码失败:", error.code, error.category, error.message);
    if (error.code === "invalid_argument") {
      console.error(error.message || "验证码已过期或不正确，请重新获取");
    } else if (error.code === "unauthenticated") {
      console.error("登录已过期，请重新登录");
      window.location.href = "/login";
    } else {
      console.error("重置密码失败:", error.message);
    }
    return false;
  } else {
    console.log("密码重置成功，已自动登录");
    return true;
  }
}

// 调用示例
await startPasswordReset("user@example.com");
// 用户输入验证码后
await completePasswordReset("123456", "newSecurePassword123");
```

</TabItem>

<TabItem value="3" label="错误处理" default>

```typescript
try {
  // 第一步：发送验证码（发送阶段错误处理）
  const { data, error } = await auth.resetPasswordForEmail("user@example.com");

  if (error) {
    console.error("发送验证码失败:", error.code, error.category, error.message);
    switch (error.code) {
      case "invalid_argument":
        console.error("邮箱格式错误，请检查邮箱格式");
        break;
      case "failed_precondition":
        console.error("账号不存在，请检查邮箱是否正确");
        break;
      case "resource_exhausted":
        console.error("发送频率过高，请稍后再试");
        break;
      case "unreachable":
        console.error("网络连接失败，请检查网络设置后重试");
        break;
      default:
        console.error("发送验证码失败:", error.message);
    }
    return;
  }

  // 第二步：验证验证码并设置新密码（verify 阶段错误处理）
  const { data: loginData, error: verifyError } = await data.updateUser({
    nonce: "123456",
    password: "newSecurePassword123",
  });

  if (verifyError) {
    console.error("重置密码失败:", verifyError.code, verifyError.category, verifyError.message);
    switch (verifyError.code) {
      case "invalid_argument":
        // 验证码过期/不正确/不匹配
        console.error(
          verifyError.message || "验证码已过期或不正确，请重新获取"
        );
        break;
      case "unauthenticated":
        // Token 失效，需要重新登录
        console.error("认证失效，请重新登录");
        window.location.href = "/login";
        break;
      case "failed_precondition":
        // 账号已被绑定等
        console.error(verifyError.message);
        break;
      case "not_found":
        console.error("用户不存在");
        break;
      case "unavailable":
        console.error("服务暂不可用，请稍后再试");
        break;
      default:
        console.error("重置密码失败:", verifyError.message);
    }
  } else {
    console.log("密码重置成功");
  }
} catch (error) {
  console.error("网络错误:", error);
}
```

</TabItem>

</Tabs>
</ApiIntro>

---

## resetPasswordForOld

```typescript
async resetPasswordForOld(params: ResetPasswordForOldReq): Promise<SignInRes>
```

通过旧密码重置当前登录用户的密码。

- 通过验证旧密码来重置当前登录用户的密码
- 需要用户已登录状态
- 适用于用户记得旧密码的场景

<ApiIntro parameter={{
input: [
{
name: "params",
type: "ResetPasswordForOldReq",
children: [{
name: "new_password",
type: "string",
required: true,
description: "新密码",
},
{
name: "old_password",
type: "string",
required: true,
description: "旧密码",
},]
}
],
output: [{
name: "Promise",
type: "SignInRes",
children: [{
name: "data",
type: "SignInResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "更新后的用户信息",
},
{
name: "session",
type: "Session",
required: true,
description: "更新后的会话信息",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="基础密码重置" default>

```typescript
const { data, error } = await auth.resetPasswordForOld({
  new_password: "newSecurePassword123",
  old_password: "oldPassword123",
});

if (error) {
  console.error("密码重置失败:", error.message);
} else {
  console.log("密码重置成功");
  console.log("用户信息:", data.user);
  console.log("会话信息:", data.session);
}
```

</TabItem>

<TabItem value="2" label="密码重置页面实现" default>

```typescript
async function changePassword(oldPassword, newPassword) {
  const { data, error } = await auth.resetPasswordForOld({
    new_password: newPassword,
    old_password: oldPassword,
  });

  if (error) {
    switch (error.code) {
      case "invalid_password":
        alert("旧密码不正确");
        break;
      case "password_too_weak":
        alert("新密码强度不够，请使用更复杂的密码");
        break;
      default:
        alert("密码重置失败: " + error.message);
    }
    return false;
  } else {
    alert("密码重置成功");
    return true;
  }
}

// 表单提交事件
document
  .getElementById("passwordForm")
  .addEventListener("submit", async (e) => {
    e.preventDefault();

    const oldPassword = document.getElementById("oldPassword").value;
    const newPassword = document.getElementById("newPassword").value;
    const confirmPassword = document.getElementById("confirmPassword").value;

    if (newPassword !== confirmPassword) {
      alert("新密码和确认密码不一致");
      return;
    }

    const success = await changePassword(oldPassword, newPassword);
    if (success) {
      // 跳转到首页或用户中心
      window.location.href = "/dashboard";
    }
  });
```

</TabItem>

<TabItem value="3" label="密码强度验证" default>

```typescript
function validatePassword(password) {
  const minLength = 8;
  const hasUpperCase = /[A-Z]/.test(password);
  const hasLowerCase = /[a-z]/.test(password);
  const hasNumbers = /\d/.test(password);
  const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password);

  return (
    password.length >= minLength &&
    hasUpperCase &&
    hasLowerCase &&
    hasNumbers &&
    hasSpecialChar
  );
}

async function resetPasswordWithValidation(oldPassword, newPassword) {
  if (!validatePassword(newPassword)) {
    alert("密码必须包含大小写字母、数字和特殊字符，且长度不少于8位");
    return false;
  }

  const { data, error } = await auth.resetPasswordForOld({
    new_password: newPassword,
    old_password: oldPassword,
  });

  if (error) {
    alert("密码重置失败: " + error.message);
    return false;
  }

  alert("密码重置成功");
  return true;
}
```

</TabItem>

<TabItem value="4" label="错误处理" default>

```typescript
try {
  const { data, error } = await auth.resetPasswordForOld({
    new_password: "newPassword123",
    old_password: "wrongOldPassword",
  });

  if (error) {
    switch (error.code) {
      case "invalid_password":
        console.error("旧密码不正确，请重新输入");
        document.getElementById("oldPassword").classList.add("error");
        break;
      case "password_too_weak":
        console.error("新密码强度不足，请使用更复杂的密码");
        document.getElementById("newPassword").classList.add("error");
        break;
      case "user_not_found":
        console.error("用户不存在，请重新登录");
        window.location.href = "/login";
        break;
      case "token_expired":
        console.error("会话已过期，请重新登录");
        window.location.href = "/login";
        break;
      case "permission_denied":
        console.error("权限不足，无法修改密码");
        break;
      case "unreachable":
        console.error("网络连接失败，请检查网络设置后重试");
        break;
      case "resource_exhausted":
        console.error("重置频率过高，请稍后重试");
        break;
      default:
        console.error("密码重置失败:", error.message);
    }
  } else {
    console.log("密码重置成功");
  }
} catch (error) {
  console.error("网络错误:", error);
}
```

</TabItem>

</Tabs>
</ApiIntro>

---

## reauthenticate

```typescript
async reauthenticate(): Promise<ReauthenticateRes>
```

重新认证当前登录用户身份，通过验证码验证并允许修改密码。

:::info 提示
`短信验证码` 仅支持 `上海` 地域
:::

- 重新认证当前已登录用户的身份，支持更新密码
- 通过发送验证码到用户注册的邮箱或手机号进行验证，优先选用邮箱，如果用户未设置邮箱则使用手机号
- 适用于安全敏感操作前的身份验证

<ApiIntro parameter={{
input: [],
output: [{
name: "Promise",
type: "ReauthenticateRes",
children: [{
name: "data",
type: "ReauthenticateResData",
required: true,
description: "",
children: [
{
name: "updateUser",
type: "(attributes: UpdateUserAttributes) => Promise<SignInRes>",
required: true,
description: "验证码回调函数，支持新密码参数",
children: [{
name: "attributes",
type: "UpdateUserAttributes",
required: true,
description: "状态变化回调函数入参",
children: [
{
name: "nonce",
type: "string",
required: true,
description: "验证码",
},
{
name: "password",
type: "string",
description: "新密码，如果传入则会更新密码",
}
]
},
{
name: "return",
type: "Promise<SignInRes>",
required: true,
description: "返回",
children: [{
name: "data",
type: "SignInResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "用户详细信息，包含身份信息和元数据",
},
{
name: "session",
type: "Session",
required: true,
description: "会话信息，包含访问令牌和刷新令牌",
},
]
},{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
},
],
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="重新认证并修改密码" default>

```typescript
// 第一步：发送验证码（使用当前用户信息）
const { data, error } = await auth.reauthenticate();

if (error) {
  console.error("发送验证码失败:", error.message);
} else {
  console.log("验证码已发送，等待用户输入...");

  // 第二步：等待用户输入验证码和新密码
  const verificationCode = "123456"; // 用户输入的验证码
  const newPassword = "newSecurePassword123"; // 用户输入的新密码

  // 第三步：验证验证码并设置新密码
  const { data: loginData, error: loginError } = await data.updateUser({
    nonce: verificationCode,
    password: newPassword,
  });

  if (loginError) {
    console.error("重新认证失败:", loginError.code, loginError.category, loginError.message);
    switch (loginError.code) {
      case "invalid_argument":
        console.error(loginError.message || "验证码已过期或不正确，请重新获取");
        break;
      case "unauthenticated":
        console.error("认证失效，请重新登录");
        break;
      case "unavailable":
        console.error("服务暂不可用，请稍后再试");
        break;
      default:
        console.error("重新认证失败:", loginError.message);
    }
  } else {
    console.log("重新认证成功，密码已更新");
    console.log("用户信息:", loginData.user);
  }
}
```

</TabItem>

<TabItem value="2" label="安全操作前的身份验证" default>

```typescript
async function verifyIdentityBeforeSensitiveOperation() {
  // 在执行敏感操作前重新认证用户
  const { data, error } = await auth.reauthenticate();

  if (error) {
    console.error("身份验证失败:", error.message);
    return false;
  }

  console.log("验证码已发送到您的邮箱/手机，请输入验证码继续");

  // 显示验证码输入界面
  document.getElementById("verificationModal").style.display = "block";

  return new Promise((resolve) => {
    // 等待用户输入验证码
    document.getElementById("verifyBtn").addEventListener("click", async () => {
      const code = document.getElementById("code").value;
      const newPassword = document.getElementById("newPassword").value;

      const { data: verifyData, error: verifyError } = await data.updateUser({
        nonce: code,
        password: newPassword,
      });

      if (verifyError) {
        console.error("验证失败:", verifyError.code, verifyError.category, verifyError.message);
        if (verifyError.code === "invalid_argument") {
          console.error(
            verifyError.message || "验证码已过期或不正确，请重新获取"
          );
        } else if (verifyError.code === "unauthenticated") {
          console.error("认证失效，请重新登录");
          window.location.href = "/login";
        } else {
          console.error("验证失败:", verifyError.message);
        }
        resolve(false);
      } else {
        console.log("身份验证成功，继续执行敏感操作");
        document.getElementById("verificationModal").style.display = "none";
        resolve(true);
      }
    });
  });
}

// 执行敏感操作前验证身份
if (await verifyIdentityBeforeSensitiveOperation()) {
  // 执行敏感操作
  performSensitiveOperation();
}
```

</TabItem>

<TabItem value="3" label="错误处理" default>

```typescript
try {
  const { data, error } = await auth.reauthenticate();

  if (error) {
    switch (error.code) {
      case "user_not_found":
        console.error("用户未登录，请先登录");
        window.location.href = "/login";
        break;
      case "email_not_set":
        console.error("用户未设置邮箱，无法发送验证码，请先设置邮箱地址");
        break;
      case "phone_not_set":
        console.error("用户未设置手机号，无法发送验证码，请先设置手机号码");
        break;
      case "resource_exhausted":
        console.error("发送频率过高，请稍后再试");
        break;
      case "unreachable":
        console.error("网络连接失败，请检查网络设置后重试");
        break;
      case "permission_denied":
        console.error("权限不足，请检查安全域名配置");
        break;
      default:
        console.error("发送验证码失败:", error.message);
    }
  }
} catch (error) {
  console.error("网络错误:", error);
}
```

</TabItem>

<TabItem value="4" label="验证码验证错误处理" default>

```typescript
async function verifyReauthenticationCode(code, newPassword) {
  try {
    const { data, error } = await auth.reauthenticate();

    if (error) {
      console.error("发送验证码失败:", error.message);
      return false;
    }

    const { data: verifyData, error: verifyError } = await data.updateUser({
      nonce: code,
      password: newPassword,
    });

    if (verifyError) {
      console.error("验证失败:", verifyError.code, verifyError.category, verifyError.message);
      switch (verifyError.code) {
        case "invalid_argument":
          // 验证码过期/不正确/参数缺失（如密码强度不足）
          console.error(
            verifyError.message || "验证码已过期或不正确，请重新获取"
          );
          break;
        case "unauthenticated":
          // Token 失效，需要重新登录
          console.error("认证失效，请重新登录");
          window.location.href = "/login";
          break;
        case "failed_precondition":
          // 账号已被绑定等业务校验
          console.error(verifyError.message);
          break;
        case "not_found":
          // 用户不存在
          console.error("用户不存在，请重新登录");
          window.location.href = "/login";
          break;
        case "unavailable":
          // 服务端异常
          console.error("服务暂不可用，请稍后再试");
          break;
        case "unreachable":
          console.error("网络连接失败，请检查网络设置后重试");
          break;
        default:
          console.error("验证失败:", verifyError.message);
      }
      return false;
    } else {
      console.log("重新认证成功");
      return true;
    }
  } catch (error) {
    console.error("网络错误:", error);
    return false;
  }
}
```

</TabItem>

</Tabs>
</ApiIntro>

## 验证管理

## verifyOAuth

```typescript
async verifyOAuth(params?: VerifyOAuthReq): Promise<SignInRes>
```

验证第三方平台授权回调，完成 OAuth 登录流程。

- 验证第三方平台授权回调，获取用户信息并完成登录，可以配合[signInWithOAuth](#signinwithoauth)使用
- 支持自动从 URL 参数获取授权码和状态参数
- 提供完整的安全验证机制，防止 CSRF 攻击
- 验证完成后可以手动配置要跳转的页面

<ApiIntro parameter={{
input: [
{
name: "params",
type: "VerifyOAuthReq",
children: [
{
name: "code",
type: "string",
description: "授权码（默认从 URL 参数获取）",
},
{
name: "state",
type: "string",
description: "状态参数（默认从 URL 参数获取）",
},
{
name: "provider",
type: "string",
description: "第三方平台标识（默认从 sessionStorage 获取）",
},
]
}
],
output: [{
name: "Promise",
type: "VerifyOAuthRes",
children: [{
name: "data",
type: "VerifyOAuthResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "用户信息",
},
{
name: "session",
type: "Session",
required: true,
description: "会话信息",
},
{
name: "redirectUrl",
type: "string",
required: true,
description: "跳转URL，跳转第三方授权之前的URL或用户调用 signInWithOAuth 时传入的redirectTo",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="自动从URL参数验证" default>

```typescript
// 在授权回调页面调用，自动获取URL参数
const { data, error } = await auth.verifyOAuth();

if (error) {
  console.error("授权验证失败:", error.message);
} else {
  console.log("授权成功，用户信息:", data.user);
  console.log("会话信息:", data.session);

  // 验证成功后跳转到首页
  window.location.href = "/home";
}
```

</TabItem>

<TabItem value="2" label="手动传入参数验证" default>

```typescript
// 手动获取URL参数并验证
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get("code");
const state = urlParams.get("state");

const { data, error } = await auth.verifyOAuth({
  code: code,
  state: state,
  provider: "wechat",
});

if (error) {
  console.error("微信授权验证失败:", error.message);
} else {
  console.log("微信授权成功，用户昵称:", data.user?.user_metadata?.nickName);
}
```

</TabItem>

<TabItem value="3" label="完整的OAuth登录流程" default>

```typescript
// 第一步：生成授权链接
const { data, error } = await auth.signInWithOAuth({
  provider: "wechat",
  options: {
    redirectTo: "https://example.com/oauth-callback",
    state: "wx_oauth_20241204",
  },
});

if (error) {
  console.error("获取授权链接失败:", error.message);
  return;
}

// 第二步：跳转到授权页面
window.location.href = data.url;

// 在回调页面（oauth-callback）中：
// 第三步：验证授权结果
const { data: verifyData, error: verifyError } = await auth.verifyOAuth();

if (verifyError) {
  console.error("授权验证失败:", verifyError.code, verifyError.category, verifyError.message);
} else {
  console.log("授权成功，用户已登录");
  window.location.href = "/dashboard";
}
```

</TabItem>

<TabItem value="4" label="错误处理" default>

```typescript
try {
  const { data, error } = await auth.verifyOAuth();

  if (error) {
    switch (error.code) {
      case "invalid_code":
        console.error("授权码无效或已过期，请重新授权");
        break;
      case "state_mismatch":
        console.error("状态参数不匹配，可能存在安全风险，请重新授权");
        break;
      case "provider_mismatch":
        console.error("第三方平台标识不匹配，请检查平台配置");
        break;
      case "failed_precondition":
        console.error("从第三方获取用户信息失败，请检查平台配置");
        break;
      case "resource_exhausted":
        console.error("请求频率过高，请稍后重试");
        break;
      case "permission_denied":
        console.error("权限不足，请检查安全域名配置");
        break;
      case "unreachable":
        console.error("网络连接失败，请检查网络设置后重试");
        break;
      case "invalid_code":
        console.error("授权码无效或已过期，请重新授权");
        break;
      case "state_mismatch":
        console.error("状态参数不匹配，可能存在安全风险，请重新授权");
        break;
      default:
        console.error("授权验证失败:", error.message);
    }

  } else {
    console.log("授权验证成功");
  }
} catch (error) {
  console.error("网络错误:", error);
}
```

</TabItem>

</Tabs>
</ApiIntro>

---

## verifyOtp

```typescript
async verifyOtp(params: VerifyOtpParams): Promise<AuthResponse>
```

独立校验一次性密码（OTP）并登录。只登录、不注册。

:::info 提示
`短信验证码` 仅支持 `上海` 地域
:::

:::warning 独立调用必须传 `messageId`
`auth.verifyOtp(params)` 的 `messageId` **必填**。缺参时 SDK 返回客户端校验错误（`error.code === "missing_required_param"`，`error.errorCode === 4000`），错误信息形如：

```
auth.verifyOtp(params): missing required param 'messageId'
```

这是前端入参问题，不是发码通道未配置。

**两条路径不要混用：**

| 发码方式 | 校验方式 | `messageId` |
| --- | --- | --- |
| `signInWithOtp` / `signUp` | 返回的 `data.verifyOtp({ token })` | 不必传（SDK 已缓存） |
| `getVerification` / `resend` | 独立 `auth.verifyOtp({ token, messageId })` | **必填**，取 `verification_id` 或 `data.messageId` |

推荐使用 `signInWithOtp` / `signUp` 返回的回调，避免手动传参遗漏。
:::

- 验证通过邮箱或手机号发送的一次性密码（OTP）
- 支持邮箱和手机号两种验证方式（二选一）
- 验证成功后自动登录用户并返回会话信息
- 独立调用只登录、不注册；需要自动注册请用 `signInWithOtp` / `signUp` 的回调

<ApiIntro parameter={{
input: [
{
name: "params",
type: "VerifyOtpParams",
children: [
{
name: "email",
type: "string",
description: "邮箱地址（与手机号二选一）",
},
{
name: "phone",
type: "string",
description: "手机号码（与邮箱二选一）",
},
{
name: "token",
type: "string",
required: true,
description: "验证码",
},
{
name: "messageId",
type: "string",
required: true,
description: "验证码对应 ID（独立调用必填）。来自 getVerification() 的 verification_id 或 resend() 的 data.messageId。signInWithOtp/signUp 返回的 data.verifyOtp 回调里该字段可选",
},
]
}
],
output: [{
name: "Promise",
type: "SignInRes",
children: [{
name: "data",
type: "SignInResData",
required: true,
description: "",
children: [
{
name: "user",
type: "User",
required: true,
description: "用户信息",
},
{
name: "session",
type: "Session",
required: true,
description: "会话信息",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="推荐：signInWithOtp 回调" default>

```typescript
// 推荐：发码接口返回的回调已缓存 messageId，只需传 token
const { data, error } = await auth.signInWithOtp({
  phone: "13800138000",
});

if (error) {
  console.error("发送验证码失败:", error.message);
  return;
}

const { data: loginData, error: loginError } = await data.verifyOtp({
  token: "123456",
});

if (loginError) {
  console.error("验证失败:", loginError.message);
} else {
  console.log("登录成功，用户信息:", loginData.user);
  console.log("会话信息:", loginData.session);
}
```

</TabItem>

<TabItem value="2" label="getVerification + verifyOtp" default>

```typescript
const email = "user@example.com";

// 1. 独立发码：必须保存 verification_id，后续作为 messageId 传入
const verificationInfo = await auth.getVerification({
  email,
});

// 2. 独立校验：messageId 必填，缺省会返回 missing_required_param
const { data, error } = await auth.verifyOtp({
  email,
  token: "654321",
  messageId: verificationInfo.verification_id,
});

if (error) {
  console.error("邮箱验证失败:", error.code, error.message);
} else {
  console.log("邮箱验证成功，用户邮箱:", data.user?.email);
}
```

</TabItem>

<TabItem value="3" label="resend + verifyOtp">

```typescript
const phone = "13800138000";

// 1. 重发验证码，拿到新的 messageId
const { data, error: resendError } = await auth.resend({ phone });
if (resendError) {
  console.error("重发失败:", resendError.message);
  return;
}

// 2. 独立校验必须带上新的 messageId
const { data: verifyData, error } = await auth.verifyOtp({
  phone,
  token: "123456",
  messageId: data.messageId,
});

if (error) {
  console.error("验证失败:", error.message);
} else {
  console.log("验证成功，用户信息:", verifyData.user);
  console.log("会话信息:", verifyData.session);
}
```

</TabItem>

<TabItem value="4" label="错误处理" default>

```typescript
try {
  const { data, error } = await auth.verifyOtp({
    phone: "13800138000",
    token: "123456",
    // 若漏传 messageId，会得到客户端校验错误，而不是服务端通道错误
    messageId: "verification_id_from_getVerification",
  });

  if (error) {
    switch (error.code) {
      case "missing_required_param":
        // 4xx：前端入参缺失。error.message 带调用点，如
        // auth.verifyOtp(params): missing required param 'messageId'
        console.error("缺少必填参数:", error.message);
        console.error("请补上 params.messageId，或改用 signInWithOtp 返回的 data.verifyOtp");
        break;
      case "invalid_argument":
        console.error("验证码错误，请重新输入");
        document.getElementById("code").classList.add("error");
        break;
      case "code_expired":
        console.error("验证码已过期，请重新获取");
        document.getElementById("resendBtn").style.display = "block";
        break;
      case "max_attempts_exceeded":
        console.error("验证次数过多，请稍后再试");
        document.getElementById("verifyBtn").disabled = true;
        break;
      default:
        console.error("验证失败:", error.code, error.category, error.message);
    }
  } else {
    console.log("验证成功", data.user);
  }
} catch (error) {
  console.error("网络错误:", error);
}
```

</TabItem>

</Tabs>
</ApiIntro>

---

## resend

```typescript
async resend(params: ResendParams): Promise<ResendRes>
```

重新发送验证码到邮箱或手机号。

:::info 提示
`短信验证码` 仅支持 `上海` 地域
:::

- 向用户重新发送邮箱或手机号的验证码
- 支持注册、邮箱变更、手机号变更等场景
- 重新发送后获取新的消息 ID，用于后续验证流程
- 提供频率限制保护，防止恶意重发

<ApiIntro parameter={{
input: [
{
name: "params",
type: "ResendParams",
children: [
{
name: "email",
type: "string",
description: "邮箱地址（与手机号二选一）",
},
{
name: "phone",
type: "string",
description: "手机号码（与邮箱二选一）",
},
{
name: "type",
type: "string",
description: "验证码类型，可选值: 'signup' | 'email_change' | 'phone_change' | 'sms'",
},
]
}
],
output: [{
name: "Promise",
type: "ResendRes",
children: [{
name: "data",
type: "ResendResData",
required: true,
description: "",
children: [
{
name: "messageId",
type: "string",
required: true,
description: "消息 ID（验证码 ID）",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="重新发送手机验证码" default>

```typescript
// 第一次发送验证码
const { data, error } = await auth.signInWithOtp({ phone: "13800138000" });

// 验证码校验回调
let signUpVerify = data.verifyOtp;

// 重新发送验证码，获取新的messageId
const { data: resendData, error: resendError } = await auth.resend({
  phone: "13800138000",
  type: "signup",
});

if (resendError) {
  console.error("重发验证码失败:", resendError.message);
  console.error("错误代码:", resendError.code);
} else {
  console.log("验证码已重发，消息ID:", resendData.messageId);

  // 将新的messageId传入signInWithOtp()或signUp()的callback参数
  const verificationCode = "123456"; // 用户输入的验证码
  const messageId = resendData.messageId; // 新的messageId

  // 使用新的messageId进行验证
  const { data: loginData, error: loginError } = await signUpVerify({
    token: verificationCode,
    messageId,
  });

  if (loginError) {
    console.error("验证失败:", loginError.message);
  } else {
    console.log("验证成功");
  }

  // 开始倒计时
  startCountdown(60);
}
```

</TabItem>

<TabItem value="2" label="重新发送邮箱验证码" default>

```typescript
const { data, error } = await auth.resend({
  email: "user@example.com",
  type: "email_change",
});

if (error) {
  console.error("重发邮箱验证码失败:", error.message);
} else {
  console.log("邮箱验证码已重发");

  // 显示提示信息
  document.getElementById("resendStatus").innerText =
    "验证码已重新发送到您的邮箱";
}
```

</TabItem>

<TabItem value="3" label="注册页面的重发功能" default>

```typescript
let countdown = 0;
let countdownInterval;

function startCountdown(seconds) {
  countdown = seconds;
  const resendBtn = document.getElementById("resendBtn");

  resendBtn.disabled = true;
  resendBtn.innerText = `${countdown}秒后可重发`;

  countdownInterval = setInterval(() => {
    countdown--;
    resendBtn.innerText = `${countdown}秒后可重发`;

    if (countdown <= 0) {
      clearInterval(countdownInterval);
      resendBtn.disabled = false;
      resendBtn.innerText = "重新发送验证码";
    }
  }, 1000);
}

async function resendVerificationCode() {
  const email = document.getElementById("email").value;

  if (!email) {
    alert("请输入邮箱地址");
    return;
  }

  const { data, error } = await auth.resend({
    email: email,
    type: "signup",
  });

  if (error) {
    alert("重发失败: " + error.message);
  } else {
    alert("验证码已重新发送到您的邮箱");
    startCountdown(60); // 60秒倒计时
  }
}

// 重发按钮点击事件
document
  .getElementById("resendBtn")
  .addEventListener("click", resendVerificationCode);
```

</TabItem>

<TabItem value="4" label="错误处理" default>

```typescript
try {
  const { data, error } = await auth.resend({
    phone: "13800138000",
    type: "signup",
  });

  if (error) {
    switch (error.code) {
      case "resource_exhausted":
        console.error("发送频率过高，请稍后再试");
        document.getElementById("resendBtn").disabled = true;
        setTimeout(() => {
          document.getElementById("resendBtn").disabled = false;
        }, 60000); // 1分钟后重试
        break;
      case "invalid_phone":
        console.error("手机号格式错误");
        break;
      case "invalid_email":
        console.error("邮箱格式错误");
        break;
      default:
        console.error("重发失败:", error.message);
    }
  } else {
    console.log("重发成功");
  }
} catch (error) {
  console.error("网络错误:", error);
}
```

</TabItem>

</Tabs>
</ApiIntro>

## 其他工具

## onAuthStateChange

```typescript
onAuthStateChange(callback: OnAuthStateChangeCallback): OnAuthStateChangeResult
```

监听认证状态变化，实时响应登录、登出、令牌刷新等事件。

- 监听用户认证状态的变化事件
- 支持多种事件类型：登录、登出、令牌刷新、用户信息更新、身份源绑定等
- 返回订阅对象，用于取消监听
- 适用于构建响应式 UI 和状态管理

<ApiIntro parameter={{
input: [
{
name: "callback",
type: "OnAuthStateChangeCallback",
description: "状态变化回调函数",
children: [{
name: "params",
type: "OnAuthStateChangeCallbackParams",
required: true,
description: "状态变化回调函数入参",
children: [
{
name: "event",
type: "OnAuthStateChangeEvent",
required: true,
description: "事件标识，包含 'INITIAL_SESSION' | 'SIGNED_IN' | 'SIGNED_OUT' | 'PASSWORD_RECOVERY' | 'TOKEN_REFRESHED' | 'USER_UPDATED' | 'BIND_IDENTITY'",
},
{
name: "session",
type: "Session",
required: true,
description: "会话信息，包含访问令牌和刷新令牌",
},
{
name: "info",
type: "Info",
description: "回调信息，如果info.error存在，则表示回调失败",
children: [
  {
    name: "type",
type: "'sign_in' | 'bind_identity' | ''",
required: true,
description: "类型，sign_in: 登录，bind_identity: 绑定身份",
  },
  {
    name: "error",
type: "AuthError",
required: true,
description: "不为null，则表示回调执行失败，例如登录失败（类型为类型，sign_in），绑定身份失败（类型为bind_identity）",
  }
]
}
]
},
{
name: "return",
type: "void",
required: true,
description: "状态变化回调函数返回",
}]
}
],
output: [{
name: "OnAuthStateChangeResult",
type: "object",
children: [{
name: "data",
type: "OnAuthStateChangeResultData",
required: true,
description: "",
children: [
{
name: "subscription",
type: "Subscription",
required: true,
description: "订阅对象，用于取消监听",
children: [
{
name: "id",
type: "string",
required: true,
description: "订阅 ID",
},
{
name: "callback",
type: "OnAuthStateChangeCallback",
required: true,
description: "回调函数，与传入的参数 callback 相同"
},
{
name: "unsubscribe",
type: "() => void",
required: true,
description: "取消订阅方法",
},
]
},
]
}],
}]
}}
> 
<Tabs>
<TabItem value="1" label="监听所有认证状态变化" default>

```typescript
const { data } = auth.onAuthStateChange((event, session, info) => {
  console.log("认证状态变化:", event, session, info);

  switch (event) {
    case "INITIAL_SESSION":
      console.log("初始会话已建立");
      if (session) {
        console.log("用户已登录:", session.user?.id);
      } else {
        console.log("用户未登录");
      }
      break;

    case "SIGNED_IN":
      console.log("用户登录成功:", session.user?.id);
      // 更新UI显示
      document.getElementById("loginBtn").style.display = "none";
      document.getElementById("userInfo").style.display = "block";
      document.getElementById("userId").innerText = session.user?.id || "";
      break;

    case "SIGNED_OUT":
      console.log("用户已登出");
      // 更新UI显示
      document.getElementById("loginBtn").style.display = "block";
      document.getElementById("userInfo").style.display = "none";
      break;

    case "PASSWORD_RECOVERY":
      console.log("密码已重置");
      // 显示密码重置界面
      document.getElementById("passwordResetForm").style.display = "block";
      break;

    case "TOKEN_REFRESHED":
      console.log("令牌已刷新");
      break;

    case "USER_UPDATED":
      console.log("用户信息已更新");
      // 更新用户信息显示
      if (session) {
        document.getElementById("userId").innerText = session.user?.id || "";
        document.getElementById("userAvatar").src =
          session.user?.user_metadata?.avatarUrl || "";
      }
      break;

    case "BIND_IDENTITY":
      console.log("身份源绑定结果");
      if (!!info.error) {
        console.log("身份源绑定失败");
      } else {
        console.log("身份源已绑定");
      }
      break;
  }
});

// 取消监听（在组件卸载时调用）
// data.subscription.unsubscribe();
```

</TabItem>

<TabItem value="2" label="React组件中的使用" default>

```typescript
import { useEffect, useState } from "react";

function AuthStatus() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const { data } = auth.onAuthStateChange((event, session, info) => {
      setLoading(false);

      if (event === "SIGNED_IN" || event === "INITIAL_SESSION") {
        setUser(session?.user || null);
      } else if (event === "SIGNED_OUT") {
        setUser(null);
      }
    });

    // 清理函数
    return () => {
      data.subscription.unsubscribe();
    };
  }, []);

  if (loading) {
    return <div>加载中...</div>;
  }

  return (
    <div>
      {user ? (
        <div>
          <p>欢迎，{user.email}</p>
          <button onClick={() => auth.signOut()}>退出登录</button>
        </div>
      ) : (
        <div>
          <p>请先登录</p>
          <button
            onClick={() =>
              auth.signInWithPassword({
                /* 登录参数 */
              })
            }
          >
            登录
          </button>
        </div>
      )}
    </div>
  );
}
```

</TabItem>

<TabItem value="3" label="路由守卫" default>

```typescript
// 路由守卫组件
function RouteGuard({ children }) {
  const [authenticated, setAuthenticated] = useState(false);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const { data } = auth.onAuthStateChange((event, session, info) => {
      setLoading(false);

      if (event === "SIGNED_IN" || event === "INITIAL_SESSION") {
        if (session) {
          setAuthenticated(true);
        } else {
          setAuthenticated(false);
        }
      } else if (event === "SIGNED_OUT") {
        setAuthenticated(false);
      }
    });

    return () => {
      data.subscription.unsubscribe();
    };
  }, []);

  if (loading) {
    return <div>检查登录状态...</div>;
  }

  if (!authenticated) {
    // 未登录，重定向到登录页
    window.location.href = "/login";
    return <div>重定向到登录页...</div>;
  }

  return children;
}

// 使用路由守卫
function App() {
  return (
    <div>
      <RouteGuard>
        <Dashboard />
      </RouteGuard>
    </div>
  );
}
```

</TabItem>

<TabItem value="4" label="多页面应用中的状态管理" default>

```typescript
// 全局认证状态管理
class AuthManager {
  constructor() {
    this.currentUser = null;
    this.listeners = [];
    this.setupAuthListener();
  }

  setupAuthListener() {
    const { data } = auth.onAuthStateChange((event, session, info) => {
      switch (event) {
        case "SIGNED_IN":
        case "INITIAL_SESSION":
          this.currentUser = session?.user || null;
          this.notifyListeners();
          break;
        case "SIGNED_OUT":
          this.currentUser = null;
          this.notifyListeners();
          break;
      }
    });

    this.unsubscribe = data.subscription.unsubscribe;
  }

  addListener(listener) {
    this.listeners.push(listener);
  }

  removeListener(listener) {
    this.listeners = this.listeners.filter((l) => l !== listener);
  }

  notifyListeners() {
    this.listeners.forEach((listener) => listener(this.currentUser));
  }

  destroy() {
    if (this.unsubscribe) {
      this.unsubscribe();
    }
  }
}

// 创建全局认证管理器
const authManager = new AuthManager();

// 在不同页面中使用
function PageA() {
  const [user, setUser] = useState(null);

  useEffect(() => {
    authManager.addListener(setUser);
    return () => authManager.removeListener(setUser);
  }, []);

  return <div>{user ? `欢迎，${user.email}` : "请登录"}</div>;
}
```

</TabItem>

</Tabs>
</ApiIntro>

---

## getClaims

```typescript
async getClaims(): Promise<GetClaimsRes>
```

获取当前访问令牌中的声明信息，用于调试和权限检查。

- 解析当前访问令牌的 JWT 声明信息
- 返回令牌的头部、声明和签名部分
- 用于调试令牌信息、检查权限和验证令牌状态
- 需要用户已登录状态才能获取令牌信息

<ApiIntro parameter={{
input: [],
output: [{
name: "Promise",
type: "GetClaimsRes",
children: [{
name: "data",
type: "GetClaimsResData",
required: true,
description: "",
children: [
{
name: "claims",
type: "Record<string, any>",
required: true,
description: "令牌声明信息",
defaultExpand: false,
children: [
{
name: "iss",
type: "string",
required: true,
description: "issuer",
},
{
name: "sub",
type: "string",
required: true,
description: "subject",
},
{
name: "aud",
type: "string",
required: true,
description: "audience",
},
{
name: "exp",
type: "number",
required: true,
description: "expiration time",
},
{
name: "iat",
type: "number",
required: true,
description: "issued at",
},
{
name: "at_hash",
type: "string",
required: true,
description: "access token hash",
},
{
name: "name",
type: "string",
required: true,
description: "名称",
},
{
name: "picture",
type: "string",
required: false,
description: "头像URL",
},
{
name: "email",
type: "string",
required: false,
description: "邮箱",
},
{
name: "phone_number",
type: "string",
required: false,
description: "手机号",
},
{
name: "scope",
type: "string",
required: true,
description: "授权范围",
},
{
name: "project_id",
type: "string",
required: true,
description: "项目ID",
},
{
name: "provider",
type: "string",
required: false,
description: "第三方平台标识",
},
{
name: "provider_type",
type: "string",
required: false,
description: "第三方平台类型",
},
{
name: "groups",
type: "string[]",
required: false,
description: "用户组",
},
{
name: "meta",
type: "Record<string, any>",
required: false,
description: "",
children: [
{
name: "wxOpenId",
type: "string",
required: false,
description: "",
},
{
name: "wxUnionId",
type: "string",
required: false,
description: "",
},
],
},
{
name: "user_id",
type: "string",
required: true,
description: "用户ID",
},
{
name: "roles",
type: "string[]",
required: true,
description: "角色",
},
{
name: "user_type",
type: "string",
required: true,
description: "用户类型",
},
{
name: "client_type",
type: "string",
required: true,
description: "客户端类型",
},
{
name: "is_system_admin",
type: "boolean",
required: true,
description: "是否系统管理员",
},
],
},
{
name: "header",
type: "Record<string, any>",
required: true,
description: "令牌头部信息",
defaultExpand: false,
children: [
{
name: "alg",
type: "string",
required: true,
description: "加密算法",
},
{
name: "kid",
type: "string",
required: true,
description: "令牌ID",
},
],
},
{
name: "signature",
type: "string",
required: true,
description: "令牌签名",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="获取令牌声明信息" default>

```typescript
const { data, error } = await auth.getClaims();

if (error) {
  console.error("获取声明失败:", error.message);
} else {
  console.log("令牌声明信息:", data.claims);
  console.log("令牌头部信息:", data.header);
  console.log("令牌签名:", data.signature);

  // 解析用户信息
  if (data.claims) {
    console.log("用户ID:", data.claims.sub);
    console.log("过期时间:", new Date(data.claims.exp * 1000).toLocaleString());
    console.log("签发时间:", new Date(data.claims.iat * 1000).toLocaleString());
    console.log("用户角色:", data.claims.role);
  }
}
```

</TabItem>

<TabItem value="2" label="检查令牌权限" default>

```typescript
async function checkTokenPermissions() {
  const { data, error } = await auth.getClaims();

  if (error) {
    console.error("获取令牌信息失败:", error.message);
    return false;
  }

  if (data.claims) {
    const claims = data.claims;

    // 检查令牌是否过期
    const now = Math.floor(Date.now() / 1000);
    if (claims.exp && claims.exp < now) {
      console.error("令牌已过期");
      return false;
    }

    // 检查用户角色
    if (claims.role === "admin") {
      console.log("管理员权限");
      return true;
    } else if (claims.role === "user") {
      console.log("普通用户权限");
      return true;
    } else {
      console.error("未知用户角色");
      return false;
    }
  }

  return false;
}

// 检查权限并执行操作
if (await checkTokenPermissions()) {
  console.log("有权限，继续执行...");
} else {
  console.log("无权限，操作被拒绝");
}
```

</TabItem>

<TabItem value="3" label="令牌过期检查" default>

```typescript
async function checkTokenExpiration() {
  const { data, error } = await auth.getClaims();

  if (error) {
    console.error("检查令牌失败:", error.message);
    return false;
  }

  if (data.claims) {
    const claims = data.claims;
    const now = Math.floor(Date.now() / 1000);
    const expiresAt = claims.exp;

    if (expiresAt) {
      const timeLeft = expiresAt - now;
      const minutesLeft = Math.floor(timeLeft / 60);
      const secondsLeft = timeLeft % 60;

      if (timeLeft <= 0) {
        console.error("令牌已过期，请重新登录");
        return false;
      } else if (timeLeft < 300) {
        console.warn(
          `令牌将在 ${minutesLeft}分${secondsLeft}秒后过期，建议刷新令牌`
        );
        return true;
      } else {
        console.log(`令牌有效，剩余时间: ${minutesLeft}分${secondsLeft}秒`);
        return true;
      }
    }
  }

  return false;
}

// 定期检查令牌状态
setInterval(async () => {
  const isValid = await checkTokenExpiration();
  if (!isValid) {
    console.log("令牌已过期，自动刷新...");
    await auth.refreshSession();
  }
}, 60000); // 每分钟检查一次
```

</TabItem>

</Tabs>
</ApiIntro>

## toDefaultLoginPage

```typescript
async toDefaultLoginPage(params: authModels.ToDefaultLoginPage): Promise<void>
```

跳转系统默认登录页，兼容 web 和微信小程序端。

- 支持跳转到系统默认登录页面
- 兼容 Web 端和微信小程序端
- 可配置登录页面的版本和重定向地址
- 支持携带自定义参数跳转

<details>
<summary><strong>本地调试</strong></summary>

如果开发 Web 端应用，由于 \_\_auth 登录页面静态资源存放于[静态网站托管](https://tcb.cloud.tencent.com/dev?envId=#/static-hosting)中，所以在本地调试时需要配置代理才能成功跳转 \_\_auth 登录页面。

推荐使用 [Whistle](https://wproxy.org/docs/getting-started.html) 工具进行代理配置。
\_\_auth 登录页面的访问域名可在[静态网站托管-配置信息-默认域名](https://tcb.cloud.tencent.com/dev?envId=#/static-hosting)中查看。

假设本地启动应用的访问地址为 `http://localhost:3000`，\_\_auth 登录页面的访问域名为`lowcode-xxx-xxx.tcloudbaseapp.com`，则 Whistle 代理的 Rules 配置如下：

```
https://lowcode-xxx-xxx.tcloudbaseapp.com http://localhost:3000

# 应用其他路径代理配置
```

运行应用后，通过 `https://lowcode-xxx-xxx.tcloudbaseapp.com` 即可访问应用

</details>

<ApiIntro parameter={{
input: [{
name: "params",
type: "ToDefaultLoginPageReq",
children: [{
name: "config_version",
type: "string",
description: "默认登录页面的登录配置版本，默认值'env'",
}, {
name: "redirect_uri",
type: "string",
description: "登录后重定向地址，默认为当前页面地址",
}, {
name: "app_id",
type: "string",
description: "应用 id",
}, {
name: "query",
type: "object",
description: "跳转到默认登录页要携带的参数",
}]
}],
output: [{
name: "Promise",
type: "CommonRes",
children: [{
name: "data",
type: "CommonResData",
required: true,
description: "",
children: [
{
name: "空对象",
type: "object",
required: true,
description: "无特殊意义",
},
],
},
{
name: "error",
type: "AuthError | null",
required: true,
description: "错误信息，成功时为 null",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="跳转默认登录页" default>

```js
const app = cloudbase.init({
  env: "xxxx-yyy",
  region: "ap-shanghai", // 不传默认为上海地域
});

const auth = app.auth();

await auth.toDefaultLoginPage({
  config_version: "env",
  app_id: "app-xxx",
  redirect_uri: "xxx",
});
```

</TabItem>
</Tabs>
</ApiIntro>

## 错误码 {#error-code}

### 登录错误

| 错误码             | 说明                                                 |
| ------------------ | ---------------------------------------------------- |
| not_found          | 用户不存在                                           |
| password_not_set   | 当前用户未设置密码，请使用验证码登录或第三方登录方式 |
| invalid_password   | 密码不正确                                           |
| user_pending       | 该用户未激活                                         |
| user_blocked       | 该用户被停用                                         |
| invalid_status     | 您已经超过了密码最大重试次数， 请稍后重试            |
| invalid_two_factor | 二次验证码不匹配或已过时                             |

### 注册错误

| 错误码              | 说明                                         |
| ------------------- | -------------------------------------------- |
| failed_precondition | 你输入的手机号或邮箱已被注册，请使用其他号码 |

:::info 客户端 4xx 与服务端 5xx
OTP 相关错误不要都当成 `invalid_argument`。`error.message` 会带上**调用点 + 参数路径**，例如 `auth.verifyOtp(params): missing required param 'messageId'`。

- **客户端参数校验**（可在前端修复）：`missing_required_param`（HTTP 4xx）
- **服务端通道/配置错误**（需改控制台）：`unimplemented` / `internal` / `unavailable`（HTTP 5xx）
:::

### 验证码发送相关错误（发码阶段）

发生在 `signInWithOtp`、`signUp`、`getVerification`、`resend` 等发码调用。

| 错误码                 | category             | 说明与修复动作                                                                 |
| ---------------------- | -------------------- | ------------------------------------------------------------------------------ |
| missing_required_param | INVALID_PARAMS       | 客户端缺 `email`/`phone`。按 `error.message` 补 `params.email` 或 `params.phone` |
| invalid_argument       | INVALID_PARAMS       | 手机号/邮箱格式错误。按 `error.message` 修正格式                               |
| resource_exhausted     | RATE_LIMITED         | 发送频率限制（含 `retryAfter`）。等待后重试                                    |
| failed_precondition    | PRECONDITION_FAILED  | 前置条件不满足（如从第三方获取用户信息失败）                                   |
| unimplemented          | SERVICE_ERROR        | 短信/邮件通道未配置。去控制台开启对应登录方式                                  |
| internal               | SERVICE_ERROR        | 服务端内部错误。稍后重试                                                       |
| unavailable            | SERVICE_ERROR        | 服务不可用。稍后重试                                                           |
| captcha_required       | CAPTCHA_REQUIRED     | 需要滑块验证码，按反机器人服务接入                                             |
| captcha_invalid        | CAPTCHA_INVALID      | 滑块校验失败，刷新验证码后重试                                                 |
| login_type_disabled    | PROVIDER_NOT_ENABLED | 登录方式被禁用。去控制台开启                                                   |

### 验证码校验相关错误（校验阶段）

发生在独立 `auth.verifyOtp`，或 `signUp`/`signInWithOtp` 返回的 `data.verifyOtp` 回调。

| 错误码                 | category             | 说明与修复动作                                                                                         |
| ---------------------- | -------------------- | ------------------------------------------------------------------------------------------------------ |
| missing_required_param | INVALID_PARAMS       | 独立 `auth.verifyOtp` 缺 `messageId`。补 `params.messageId`，或改用 `data.verifyOtp({ token })` 回调     |
| invalid_argument       | VERIFICATION_FAILED  | 验证码已过期或不正确。重新获取验证码                                                                   |
| not_found              | USER_NOT_FOUND       | 用户不存在（绑定手机号阶段）                                                                           |
| failed_precondition    | PRECONDITION_FAILED  | 账号已被绑定等业务校验失败                                                                             |
| unimplemented          | SERVICE_ERROR        | 通道未配置。去控制台配短信/邮件                                                                        |
| internal               | SERVICE_ERROR        | 服务端内部错误（JWK 签名失败等）。稍后重试                                                             |
| unauthenticated        | INVALID_CREDENTIALS  | Token 校验失败 / access_token 失效，需重新登录                                                         |
| permission_denied      | PROVIDER_NOT_ENABLED | 权限拒绝（如匿名用户不支持修改等）                                                                     |
| unauthorized_client    | PROVIDER_NOT_ENABLED | client 校验失败（client not found / disabled）                                                         |

### 其他错误

| 错误码      | 说明                                   |
| ----------- | -------------------------------------- |
| unreachable | 网络错误，请检查您的网络连接，稍后重试 |

### 错误描述

| 错误码            | 错误描述                                                                      | 说明                                                                                                                                                                               |
| ----------------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| permission_denied | cors permission denied,please check if \{url\} in your client \{env\} domains | 请在"[云开发平台/环境配置/安全来源/安全域名](https://tcb.cloud.tencent.com/dev?envId=#/env/safety-source)"中检查对应\{env\}环境下是否已经配置了安全域名\{url\}，配置后 10 分钟生效 |

---

## Node.js 端专属接口 {#nodejs-server-apis}

:::tip Node.js 端
以下接口仅在 Node.js 环境（云函数、云托管、自建服务器）中有效。服务端除了以下专属接口外，也可以调用上述所有客户端身份认证接口。
:::

### getUserInfo {#getuserinfo}

```typescript
auth.getUserInfo(): IGetUserInfoResult
```

获取当前请求的用户信息（同步方法，从云函数运行时环境变量中读取）。

- 同步方法，无需 `await`
- 仅在云函数/云托管环境中有效

<ApiIntro parameter={{
input: [],
output: [{
name: "IGetUserInfoResult",
type: "object",
children: [{
name: "openId",
type: "string",
description: "微信 openId，非微信授权登录则为空",
},{
name: "appId",
type: "string",
description: "微信 appId，非微信授权登录则为空",
},{
name: "uid",
type: "string",
description: "用户唯一 ID",
},{
name: "customUserId",
type: "string",
description: "开发者自定义的用户唯一 ID，非自定义登录则为空",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="基本用法" default>

```js
const cloudbase = require("@cloudbase/js-sdk");
const app = cloudbase.init({ env: "your-env-id" });

exports.main = async (event, context) => {
  const { openId, appId, uid, customUserId } = app.auth.getUserInfo();
  console.log(openId, appId, uid, customUserId);
};
```

</TabItem>
</Tabs>
</ApiIntro>

---

### getEndUserInfo {#getenduserinfo}

```typescript
async auth.getEndUserInfo(uid?: string): Promise<IGetEndUserInfoResult>
```

获取终端用户详细信息。

- 不传 `uid` 时返回当前请求用户信息
- 传入 `uid` 时调用管理端接口查询指定用户
- 使用 `API Key` 或 `Publishable Key` 时无权限调用此接口

:::tip 关于 uid
此处 `uid` 为终端用户的唯一标识，可取客户端 `auth.getSession()` 返回结果中的 `data.user.id`（用户 ID），也可取 `data.session.sub`（会话标识）。
:::

<ApiIntro parameter={{
input: [{
name: "uid",
type: "string",
description: "云开发用户身份标识（可取客户端 getSession() 的 data.user.id 或 data.session.sub）。不传则从环境变量中读取当前用户信息",
}],
output: [{
name: "Promise",
type: "IGetEndUserInfoResult",
children: [{
name: "userInfo",
type: "EndUserInfo",
required: true,
description: "云开发用户信息",
children: [{
name: "openId",
type: "string",
description: "微信 openId，非微信授权登录则为空",
},{
name: "appId",
type: "string",
description: "微信 appId，非微信授权登录则为空",
},{
name: "uid",
type: "string",
description: "用户唯一 ID",
},{
name: "customUserId",
type: "string",
description: "开发者自定义的用户唯一 ID",
},{
name: "envName",
type: "string",
description: "云开发环境名",
},{
name: "nickName",
type: "string",
description: "用户昵称",
},{
name: "email",
type: "string",
description: "用户登录邮箱",
},{
name: "username",
type: "string",
description: "用户登录用户名",
},{
name: "hasPassword",
type: "boolean",
description: "用户是否设置密码",
},{
name: "gender",
type: "string",
description: "用户性别（MALE / FEMALE / UNKNOWN）",
},{
name: "avatarUrl",
type: "string",
description: "用户头像地址",
}]
},{
name: "requestId",
type: "string",
required: true,
description: "请求唯一标识",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="获取当前用户" default>

```js
const cloudbase = require("@cloudbase/js-sdk");
const app = cloudbase.init({ env: "your-env-id" });

exports.main = async (event, context) => {
  // 不传 uid，获取当前请求的用户信息
  const { userInfo } = await app.auth.getEndUserInfo();
  console.log(userInfo);
};
```

</TabItem>
<TabItem value="2" label="查询指定用户">

```js
const cloudbase = require("@cloudbase/js-sdk");
const app = cloudbase.init({ env: "your-env-id" });

exports.main = async (event, context) => {
  const { userInfo, requestId } = await app.auth.getEndUserInfo(
    "target-user-uid"
  );
  console.log(userInfo);
};
```

</TabItem>
</Tabs>
</ApiIntro>

---

### queryUserInfo {#queryuserinfo}

```typescript
async auth.queryUserInfo(query: IUserInfoQuery): Promise<any>
```

按条件查询用户信息。

- 支持按 `uid`、`platform`、`platformId` 三种维度查询
- 若指定 `uid` 则优先使用
- 使用 `API Key` 或 `Publishable Key` 时无权限调用此接口

<ApiIntro parameter={{
input: [{
name: "query",
type: "IUserInfoQuery",
required: true,
description: "查询参数",
children: [{
name: "uid",
type: "string",
description: "用户唯一 ID（可取客户端 getSession() 的 data.user.id 或 data.session.sub），若指定该字段则优先使用",
},{
name: "platform",
type: "string",
description: "登录类型，支持 PHONE、USERNAME、EMAIL、CUSTOM",
},{
name: "platformId",
type: "string",
description: "登录标识，对应 platform 分别为手机号、用户名、邮箱、自定义登录 ID",
}]
}],
output: [{
name: "Promise",
type: "object",
children: [{
name: "userInfo",
type: "EndUserInfo",
required: true,
description: "用户信息",
},{
name: "requestId",
type: "string",
required: true,
description: "请求唯一标识",
}]
}]
}}
> 
<Tabs>
<TabItem value="1" label="按 uid 查询" default>

```js
const cloudbase = require("@cloudbase/js-sdk");
const app = cloudbase.init({ env: "your-env-id" });

exports.main = async (event, context) => {
  const res = await app.auth.queryUserInfo({ uid: "user-uid" });
  console.log(res.userInfo);
};
```

</TabItem>
<TabItem value="2" label="按手机号查询">

```js
const cloudbase = require("@cloudbase/js-sdk");
const app = cloudbase.init({ env: "your-env-id" });

exports.main = async (event, context) => {
  const res = await app.auth.queryUserInfo({
    platform: "PHONE",
    platformId: "13800138000",
  });
  console.log(res.userInfo);
};
```

</TabItem>
</Tabs>
</ApiIntro>

---

### getClientIP {#getclientip}

```typescript
auth.getClientIP(): string
```

获取客户端 IP 地址。

- 同步方法，从环境变量 `TCB_SOURCE_IP` 中读取
- 仅在云函数/云托管环境中有效

<ApiIntro parameter={{
input: [],
output: [{
name: "string",
type: "string",
description: "客户端 IP 地址",
}]
}}
> 
<Tabs>
<TabItem value="1" label="基本用法" default>

```js
const cloudbase = require("@cloudbase/js-sdk");
const app = cloudbase.init({ env: "your-env-id" });

exports.main = async (event, context) => {
  const ip = app.auth.getClientIP();
  console.log("客户端 IP:", ip);
};
```

</TabItem>
</Tabs>
</ApiIntro>

---

### createTicket {#createticket}

```typescript
async auth.createTicket(uid: string, options?: ICreateTicketOpts): Promise<string>
```

创建自定义登录凭据 Ticket，使用 RSA 私钥签发 JWT，客户端凭此 Ticket 可换取登录态。

- **仅适用于 Node.js 服务端**（云函数、云托管、自建服务器等），私钥严禁写入小程序、H5 等前端环境
- 使用前需在 `init` 时传入自定义登录私钥 `credentials`，**该字段是 `cloudbase.init()` 的顶层配置**，属于 [Node.js 端专属参数](./initialization#nodejs-params)，**不要**将其放在 `auth` 下
- 前往 [云开发平台/身份认证/登录方式](https://tcb.cloud.tencent.com/dev?#/identity/login-manage)，通过「自定义登录」下载私钥文件
- 需安装依赖：`npm install jsonwebtoken`

`credentials` 对象包含以下字段（均来自下载的私钥文件 `tcb_custom_login.json`，无需手动填写）：

| 字段             | 说明                                             |
| ---------------- | ------------------------------------------------ |
| `env_id`         | 私钥所属的环境 ID                                |
| `private_key_id` | 私钥标识，签发的 Ticket 中会携带此 ID 用于校验   |
| `private_key`    | RSA 私钥内容，用于签发 JWT，请务必妥善保管勿泄漏 |

<ApiIntro parameter={{
input: [{
name: "uid",
type: "string",
required: true,
description: "为其签发登录态的用户唯一 ID（开发者自定义，4~32 位，支持字母数字和部分特殊字符）。客户端用该票据登录后，此 uid 即成为该用户的用户 ID，对应后续 getSession() 的 data.user.id",
},{
name: "options",
type: "ICreateTicketOpts",
description: "可选配置",
children: [{
name: "refresh",
type: "number",
description: "access_token 刷新间隔（ms），默认 3600000（1 小时）",
},{
name: "expire",
type: "number",
description: "access_token 过期时间戳（ms），默认 7 天后",
}]
}],
output: [{
name: "Promise",
type: "string",
description: "返回格式为 \"{private_key_id}/@@/{jwt_token}\" 的票据字符串",
}]
}}
> 
<Tabs>
<TabItem value="1" label="基本用法" default>

```js
const cloudbase = require("@cloudbase/js-sdk");

const app = cloudbase.init({
  env: "your-env-id",
  // credentials 是 init() 的顶层配置，不要放在 auth 下
  credentials: require("/path/to/tcb_custom_login.json"),
});

exports.main = async (event, context) => {
  const ticket = await app.auth.createTicket("custom-user-id-123", {
    refresh: 3600 * 1000, // 1 小时刷新
  });
  console.log(ticket);
  // 将 ticket 返回给客户端，客户端调用 signInWithCustomTicket 完成登录
};
```

</TabItem>
<TabItem value="2" label="TypeScript（读取私钥文件）">

```typescript
import cloudbase from "@cloudbase/js-sdk";
import { readFileSync } from "node:fs";

// 从文件或环境变量读取私钥（私钥文件内容形如 { env_id, private_key_id, private_key }）
const credentials = JSON.parse(
  readFileSync(process.env.CLOUDBASE_CREDENTIALS_PATH!, "utf-8")
);

const app = cloudbase.init({
  env: process.env.CLOUDBASE_ENV_ID, // 环境 ID 在顶层
  credentials, // credentials 同样在顶层，无需自定义类型
});

export const main = async (event: unknown, context: unknown) => {
  const ticket = await app.auth.createTicket("custom-user-id-123", {
    refresh: 3600 * 1000, // 1 小时刷新
  });
  // 将 ticket 返回给客户端，客户端调用 signInWithCustomTicket 完成登录
  return { ticket };
};
```

</TabItem>
</Tabs>

:::warning 安全提示
`credentials` 中的 `private_key` 是证明管理员身份的敏感凭证，**只能在服务端使用**，严禁写入小程序、H5 或任何前端环境变量中，避免泄漏。
:::

</ApiIntro>

---

## 完整类型定义 {#complete-type-definition}

### SignInAnonymouslyCredentials

```typescript
// 匿名登录参数
interface SignInAnonymouslyCredentials {
  provider_token?: string; // 提供令牌（可选）
  captchaToken?: string; // 验证码令牌（可选）
}
```

### User

```typescript
interface User {
  id: any; // 用户ID
  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; // 用户ID
    nickName: any; // 昵称
    avatarUrl: any; // 头像URL
    location: any; // 位置
    hasPassword: any; // 是否有密码
  };
  identities: any; // 身份信息
  created_at: string; // 创建时间
  updated_at: string; // 更新时间
  is_anonymous: boolean; // 是否匿名用户
  // 新增字段
  recovery_sent_at?: string; // 密码重置发送时间
  email_change_sent_at?: string; // 邮箱变更发送时间
  phone_change_sent_at?: string; // 手机号变更发送时间
  new_email?: string; // 新邮箱地址
  new_phone?: string; // 新手机号
}
```

### Session

```typescript
interface Session {
  access_token: string; // 访问令牌
  refresh_token: string; // 刷新令牌
  expires_in: number; // 过期时间（秒）
  token_type: string; // 令牌类型
  user: User; // 用户信息
  // 新增字段
  provider_token?: string; // 第三方平台令牌
  provider_refresh_token?: string; // 第三方平台刷新令牌
  expires_at?: number; // 过期时间戳
  issued_at?: number; // 签发时间戳
  scope?: string; // 授权范围
  token_id?: string; // 令牌ID
}
```

### AuthError

```typescript
// 认证错误类型
interface AuthError extends Error {
  code: (string & {}) | undefined; // 错误代码
  category: AuthErrorCategory; // 错误分类，用于业务逻辑判断
  requestId?: string; // 请求ID
  status: number | undefined; // HTTP状态码
  helpMessage?: string; // 帮助信息，提供错误处理建议
  retryAfter?: number; // 频率限制时的重试等待秒数
  loginMethodHint?: string; // 建议使用的登录方式
  toJSON(): Record<string, unknown>; // 可序列化的错误信息
  // 常见错误代码
  // 400: 客户端错误
  // - invalid_email: 邮箱格式错误
  // - invalid_phone: 手机号格式错误
  // - invalid_password: 密码格式错误
  // - user_not_found: 用户不存在
  // - already_exists: 邮箱已存在
  // - phone_already_exists: 手机号已存在
  // - username_already_exists: 用户名已存在
  // - invalid_code: 验证码错误
  // - code_expired: 验证码已过期
  // - max_attempts_exceeded: 验证次数过多
  // - password_too_weak: 密码强度不足
  // - invalid_token: 令牌无效
  // - token_expired: 令牌已过期
  // - state_mismatch: 状态参数不匹配
  // - provider_not_supported: 不支持的第三方平台
  // - provider_mismatch: 第三方平台标识不匹配
  // - failed_precondition: 前置条件失败
  // - permission_denied: 权限不足
  // - resource_exhausted: 资源耗尽
  // - unreachable: 网络连接失败
  // - missing_required_param: 客户端缺必填参数（如独立 verifyOtp 缺 messageId）
  // - invalid_argument: 参数错误（验证码不正确或已过期，或手机号/邮箱格式错误）
  // - unimplemented: 短信/邮件通道未配置（服务端配置错误）
  // - not_found: 用户不存在（verify 阶段）
  // - unauthenticated: Token 校验失败
  // - unauthorized_client: client 校验失败
  // 500: 服务器错误
  // - internal_error: 内部服务器错误
  // - service_unavailable: 服务不可用
}

// 错误分类枚举
enum AuthErrorCategory {
  RATE_LIMITED = "RATE_LIMITED", // 频率限制
  CAPTCHA_REQUIRED = "CAPTCHA_REQUIRED", // 需要滑块验证码
  CAPTCHA_INVALID = "CAPTCHA_INVALID", // 滑块验证码校验失败
  INVALID_CREDENTIALS = "INVALID_CREDENTIALS", // 凭据无效（密码错误、Token 失效等）
  USER_NOT_FOUND = "USER_NOT_FOUND", // 用户不存在
  INVALID_PARAMS = "INVALID_PARAMS", // 参数格式错误
  PROVIDER_NOT_ENABLED = "PROVIDER_NOT_ENABLED", // 登录方式未开启
  MFA_REQUIRED = "MFA_REQUIRED", // 需要多因素认证
  SERVICE_ERROR = "SERVICE_ERROR", // 服务端错误
  NETWORK_ERROR = "NETWORK_ERROR", // 网络不可达
  PRECONDITION_FAILED = "PRECONDITION_FAILED", // 前置条件不满足（账号已绑定等）
  VERIFICATION_FAILED = "VERIFICATION_FAILED", // 验证码校验失败（过期/不正确/不匹配）
  UNKNOWN = "UNKNOWN", // 其他未分类错误
}
```

### CommonRes

```typescript
// 通用响应参数
interface CommonRes {
  data: {}; // 成功时为空对象
  error: AuthError | null; // 错误信息，成功时为null
}
```

### SignUpReq

```typescript
// 用户注册参数（四步验证流程）
interface SignUpReq {
  email?: string; // 邮箱（可选，与手机号二选一）
  phone?: string; // 手机号（可选，与邮箱二选一）
  password: string; // 密码（必填）
  username?: string; // 用户名称（可选），长度 5-24 位，支持字符中英文、数字、特殊字符（仅支持_-），不支持中文
  nickname?: string; // 昵称（可选）
  avatar_url?: string; // 头像URL（可选）
  gender?: "MALE" | "FEMALE"; // 性别（可选）
}
```

### SignOutReq

```typescript
// 用户登出参数
interface SignOutReq {
  options?: {
    // 配置选项（可选）
    redirectTo?: string; // 登出后的重定向地址
    clearStorage?: boolean; // 是否清除本地存储（默认true）
  };
}
```

### SignInWithPasswordCredentials

```typescript
// 密码登录参数
interface SignInWithPasswordCredentials {
  username?: string; // 用户名称（可选，与邮箱、手机号三选一），长度 5-24 位，支持字符中英文、数字、特殊字符（仅支持_-），不支持中文
  email?: string; // 邮箱（可选，与用户名、手机号三选一）
  phone?: string; // 手机号（可选，与用户名、邮箱三选一）
  password: string; // 密码（必填）
  /** @deprecated 请使用 options.is_encrypt。保留以向前兼容旧调用方式。 */
  is_encrypt?: boolean; // 是否加密传输（已废弃，请使用 options.is_encrypt）
  options?: {
    is_encrypt?: boolean; // 是否加密传输，默认为 false
    captchaToken?: string; // 滑块验证码 token（可选）
  }
}
```

### SignInWithIdTokenReq

```typescript
// ID令牌登录参数
interface SignInWithIdTokenReq {
  provider?: string; // 第三方平台标识（可选）
  token: string; // 第三方平台的身份令牌（必填）
  // 新增字段
  provider?: string; // 第三方平台标识（可选，与provider参数重复，保留兼容性）
}
```

### SignInWithPasswordlessCredentials

```typescript
// OTP登录参数
interface SignInWithPasswordlessCredentials {
  email?: string; // 邮箱（可选，与手机号二选一）
  phone?: string; // 手机号（可选，与邮箱二选一）
  options?: {
    shouldCreateUser?: boolean; // 如果用户不存在是否创建用户，默认为true
    emailRedirectTo?: string; // 邮箱登录回调地址，填写后则会发送认证链接至邮箱，否则发送验证码
    captchaToken?: string; // 验证码令牌（可选）
  };
}
```

### SignInWithOAuthCredentials

```typescript
// OAuth授权参数
interface SignInWithOAuthCredentials {
  provider: string; // 第三方平台标识（必填）
  options?: {
    // 配置选项（可选）
    redirectTo?: string; // 回调地址，默认为当前页面
    skipBrowserRedirect?: boolean; // 是否跳转至授权页面，默认为false
    state?: string; // 状态参数，用于安全验证，默认为随机字符串（格式：prd-{provider}-{随机字符串}）
    queryParams?: Record<string, string>; // 额外的查询参数，将合并到授权 URI 中
    type?: "sign_in" | "bind_identity"; // 类型（可选），默认为'sign_in', sign_in: 登录，bind_identity: 绑定身份
  };
}
```

### SetSessionReq

```typescript
// 会话设置参数
interface SetSessionReq {
  access_token: string; // 访问令牌（必填）
  refresh_token: string; // 刷新令牌（必填）
}
```

### VerifyOAuthReq

```typescript
// OAuth验证参数
interface VerifyOAuthReq {
  code?: string; // 授权码（可选，默认从URL参数获取）
  state?: string; // 状态参数（可选，默认从URL参数获取）
  provider?: string; // 第三方平台标识（可选，默认从session获取）
}
```

### VerifyOtpParams

```typescript
/**
 * 独立调用 `auth.verifyOtp()` 的入参。
 *
 * **必填差异**：此处 `messageId` 为必填。
 * `signInWithOtp` / `signUp` 返回的 `data.verifyOtp` 回调里 `messageId` 为可选（闭包已绑定）。
 * 推荐使用回调，避免手动传参遗漏。
 *
 * 独立 `auth.verifyOtp` 只登录、不注册（内部 `is_user` 固定为 true）。
 */
interface VerifyOtpParams {
  type?:
    | "sms"
    | "phone_change"
    | "signup"
    | "invite"
    | "magiclink"
    | "recovery"
    | "email_change"
    | "email"; // 验证类型（可选）
  email?: string; // 邮箱（与手机号二选一）
  phone?: string; // 手机号（与邮箱二选一）
  token: string; // 验证码（必填）
  messageId: string; // 验证码对应 ID（独立调用必填；回调中可选）
}
```

### UserAttributes

```typescript
// 用户信息更新参数
interface UserAttributes {
  email?: string; // 邮箱地址
  phone?: string; // 手机号
  username?: string; // 用户名称（可选），长度 5-24 位，支持中英文、数字、特殊字符（仅支持_-），不支持中文
  description?: string; // 描述（可选）
  avatar_url?: string; // 头像URL（可选）
  nickname?: string; // 昵称（可选）
  gender?: "MALE" | "FEMALE"; // 性别（可选）
}
```

### LinkIdentityReq

```typescript
// 身份源绑定参数
interface LinkIdentityReq {
  provider: string; // 身份源标识（必填）
}
```

### UnlinkIdentityReq

```typescript
// 身份源解绑参数
interface UnlinkIdentityReq {
  provider: string; // 身份源标识（必填）
}
```

### ReauthenticateReq

```typescript
// 重新认证参数
interface ReauthenticateReq {
  // 无入参，使用当前登录用户的信息
}
```

### ResendParams

```typescript
// 重发验证码参数
interface ResendParams {
  email?: string; // 邮箱（可选，与手机号二选一）
  phone?: string; // 手机号（可选，与邮箱二选一）
  type?: "signup" | "email_change" | "phone_change" | "sms"; // 类型（可选）
}
```

### ResendRes

```typescript
// 重发验证码响应参数
interface ResendRes {
  data: {
    messageId?: string; // 消息ID（验证码ID）
  };
  error: AuthError | null; // 错误信息，成功时为null
}
```

### AuthOtpResponse

```typescript
/**
 * OTP 回调参数：由 `signInWithOtp` / `signUp` 返回的 `data.verifyOtp` 所接收。
 *
 * 回调闭包已绑定 email/phone 以及发码时的 `messageId`，调用方只需传入 `token`。
 *
 * **必填差异**：回调里 `messageId` 可选；独立调用 `auth.verifyOtp(params)` 时 `messageId` 必填。
 */
interface VerifyOtpCallbackParams {
  token: string | number; // 验证码（必填）
  messageId?: string; // 可选，覆盖闭包中的 ID；一般无需传入
}

// OTP 登录响应参数
interface AuthOtpResponse {
  data: {
    /**
     * 校验验证码并完成登录/注册。只需传 `token`，不必传 `messageId`（SDK 已绑定）。
     * 与独立方法 `auth.verifyOtp` 不同：独立调用时 `messageId` 必填，且只登录不注册。
     */
    verifyOtp?: (params: VerifyOtpCallbackParams) => Promise<SignInRes>;
  };
  error: AuthError | null;
}
```

### SignUpRes

```typescript
// 用户注册响应参数
interface SignUpRes {
  data: {
    /**
     * 与 `signInWithOtp` 返回的回调相同：`messageId` 可选，SDK 已绑定。
     */
    verifyOtp?: (params: VerifyOtpCallbackParams) => Promise<SignInRes>;
  };
  error: AuthError | null;
}
```

### OAuthResponse

```typescript
// OAuth授权响应参数
interface OAuthResponse {
  data: {
    url?: string; // 授权页面URL
    provider?: string; // 第三方平台标识
    scopes?: string; // 授权范围
  };
  error: AuthError | null; // 错误信息，成功时为null
}
```

### LinkIdentityRes

```typescript
// 身份源绑定响应参数
interface LinkIdentityRes {
  data: {
    provider?: string; // 绑定的身份源标识
    type?: "sign_in" | "bind_identity" | ""; // 类型（可选），默认为'sign_in', sign_in: 登录，bind_identity: 绑定身份
  };
  error: AuthError | null; // 错误信息，成功时为null
}
```

### Identity

```typescript
interface Identity {
  id: string; // 身份源标识
  name: string; // 身份源名称
  picture: string; // 头像URL
}
```

### GetUserIdentitiesRes

```typescript
// 用户身份源获取响应参数
interface GetUserIdentitiesRes {
  data: {
    identities?: Array<{
      id: string; // 身份源标识
      name: string; // 身份源名称
      picture: string; // 头像URL
    }>;
  };
  error: AuthError | null; // 错误信息，成功时为null
}
```

### GetClaimsRes

```typescript
// 声明信息获取响应参数
interface GetClaimsRes {
  data: {
    // 令牌声明信息
    claims?: {
      iss: string; // issuer
      sub: string; // subject
      aud: string; //  audience
      exp: number; //  expiration time
      iat: number; // issued at
      at_hash: string; // access token hash
      name: string; // 名称
      picture?: string; // 头像URL
      email?: string; // 邮箱
      phone_number?: string; // 手机号
      scope: string; // 授权范围
      project_id: string; // 项目ID
      provider?: string; // 第三方平台标识
      provider_type?: string; // 第三方平台类型
      groups?: string[]; // 用户组
      meta?: {
        wxOpenId?: string;
        wxUnionId?: string;
      };
      user_id: string; // 用户ID
      roles: string[]; // 角色
      user_type: string; // 用户类型
      client_type: string; // 客户端类型
      is_system_admin: boolean; // 是否系统管理员
    };
    // 令牌头部信息
    header?: {
      alg: string; // 加密算法
      kid: string; // 令牌ID
    };
    signature?: string; // 令牌签名
  };
  error: AuthError | null; // 错误信息，成功时为null
}
```

### ResetPasswordForOldReq

```typescript
// 通过旧密码重置密码参数
interface ResetPasswordForOldReq {
  new_password: string; // 新密码（必填）
  old_password: string; // 旧密码（必填）
}
```

### DeleteMeReq

```typescript
// 删除当前用户参数
interface DeleteMeReq {
  password: string; // 用户密码（必填）
}
```

### SignInRes

```typescript
// 登录响应参数
interface SignInRes {
  data: {
    user?: User; // 用户信息
    session?: Session; // 会话信息
  };
  error: AuthError | null; // 错误信息，成功时为null
}
```

### GetUserRes

```typescript
// 用户信息获取响应参数
interface GetUserRes {
  data: {
    user?: User; // 用户详细信息
  };
  error: AuthError | null; // 错误信息，成功时为null
}
```

### OnAuthStateChangeEvent

```typescript
// 认证状态变化事件类型
type OnAuthStateChangeEvent =
  | "SIGNED_OUT" // 用户已登出
  | "SIGNED_IN" // 用户登录成功
  | "INITIAL_SESSION" // 初始会话已建立
  | "PASSWORD_RECOVERY" // 密码已重置
  | "TOKEN_REFRESHED" // 令牌已刷新
  | "USER_UPDATED" // 用户信息已更新
  | "BIND_IDENTITY"; // 身份源绑定结果
```

### OnAuthStateChangeCallback

```typescript
// 认证状态变化回调函数类型
type OnAuthStateChangeCallback = (
  event: OnAuthStateChangeEvent,
  session: Session
) => void;
```

### ResetPasswordForEmailRes

```typescript
// 邮箱重置密码响应参数
interface ResetPasswordForEmailRes {
  data: {
    updateUser?: (attributes: UpdateUserAttributes) => Promise<SignInRes>; // 验证码回调函数，支持新密码参数
  };
  error: AuthError | null; // 错误信息，成功时为null
}
```

### UpdateUserAttributes

```typescript
// 用户属性更新参数
interface UpdateUserAttributes {
  nonce: string; // 验证码
  password: string; // 新密码
}
```

### ReauthenticateRes

```typescript
// 重新认证响应参数
interface ReauthenticateRes {
  data: {
    updateUser?: (attributes: UpdateUserAttributes) => Promise<SignInRes>; // 验证码回调函数，支持新密码参数
  };
  error: AuthError | null; // 错误信息，成功时为null
}
```