v6.6.0
2026-09-01 发布的实验性抖音 Passport 扫码登录功能
v6.6.0 变更日志
抖音 Passport 扫码登录是 实验性功能,不保证稳定性。它依赖抖音 Web 端的内部登录接口、签名参数和风控策略,服务端行为变化可能随时导致功能失效。后续版本可能调整、重命名或移除相关方法、参数、返回值和底层实现,请不要在对稳定性有要求的生产登录链路中依赖当前 API。
新增:抖音 Passport 扫码登录
本版本新增一套基于 login.douyin.com Passport 体系的抖音扫码登录流程,支持:
- 获取 Passport 登录二维码;
- 轮询二维码状态;
- 处理扫码确认后的 SSO 跳转;
- 处理部分账号触发的短信二次验证;
- 提交短信验证码并获取登录 Cookie;
- 在调用之间传递会话 Cookie 和
bd-ticket-guard设备票据状态。
这套流程与原有的 requestLoginQrcode 不同。后者是旧的登录二维码接口;Passport 登录提供的是一套从取码到获取登录态的完整流程。
重要限制:目前独立于 Amagi Client 架构
Passport 登录当前是独立接入的实验性模块,尚未完整纳入 Amagi Client 的实例级架构。它与现有通过 client.douyin.fetcher 使用的稳定数据接口不是同一套内部实现:
- 当前推荐使用导出的 Passport 方法或
douyinFetcher; - 不支持通过
client.douyin.fetcher的实例 Cookie 状态自动维护登录会话; - 不支持通过
createBoundDouyinFetcher绑定并自动维护这套登录流程; - 登录过程中的会话状态必须由调用方保存每次返回的
cookie,并在下一次调用时传回; - 轮询循环也需要由调用方自行维护。
后续可能会将这套能力重构并接入统一的客户端、Fetcher 或会话管理架构。因此当前方法的调用方式和类型不能视为长期兼容的稳定 API。
当前 API
可以从包根路径导入以下方法:
import {
checkPassportQrcode,
requestPassportQrcode,
sendPassportVerifyCode,
validatePassportVerifyCode
} from '@ikenxuan/amagi'也可以通过 douyinFetcher 使用这些方法:
import { douyinFetcher } from '@ikenxuan/amagi'
const qrcode = await douyinFetcher.requestPassportQrcode()获取二维码
const result = await requestPassportQrcode()
if (!result.success) {
throw new Error(result.message)
}
console.log(result.data.content)
console.log(result.data.expires_in)
// 必须保存,用于后续轮询;其中可能包含 Passport 会话状态和实验性模块的内部状态
const cookie = result.data.cookie
const token = result.data.token返回数据包括:
| 字段 | 说明 |
|---|---|
token | 轮询二维码状态时使用的令牌 |
content | 二维码内容,可交给二维码生成器渲染 |
expire_time | 服务端返回的绝对 Unix 时间戳,单位为秒 |
expires_in | 获取二维码时计算出的剩余秒数,是一个时间快照 |
cookie | 后续调用必须继续传递的会话 Cookie |
轮询二维码状态
const status = await checkPassportQrcode({ token }, cookie)
if (!status.success) {
throw new Error(status.message)
}
switch (status.data.status) {
case 'new':
case 'scanned':
case 'busy':
// 根据 status.data.interval 等待后继续轮询
cookie = status.data.cookie
break
case 'verify':
// 使用 status.data.verify 进入短信二次验证流程
cookie = status.data.cookie
break
case 'confirmed':
cookie = status.data.cookie
console.log('登录完成:', status.data.logged_in)
break
case 'expired':
case 'risk':
case 'unknown':
console.log(status.data.message)
break
}每次调用后都应使用响应中最新的 cookie。二维码状态可能包括:
new:尚未扫码;scanned:已扫码,等待手机端确认;confirmed:已确认并尝试完成登录;verify:需要进行二次验证;expired:二维码已过期;busy:轮询过于频繁,按interval退避后重试;risk:触发风控;unknown:服务端返回了暂未适配的状态。
短信二次验证
当轮询结果为 verify 时,可以把返回的验证上下文传给发码接口:
const sendCode = await sendPassportVerifyCode(
{
verify: status.data.verify
},
status.data.cookie
)
if (!sendCode.success || !sendCode.data.ok) {
throw new Error(sendCode.success ? sendCode.data.message : sendCode.message)
}
const validateCode = await validatePassportVerifyCode(
{
verify: status.data.verify,
code: '123456',
biz_trace_id: sendCode.data.biz_trace_id,
verify_way: sendCode.data.verify_way
},
sendCode.data.cookie
)
if (!validateCode.success || !validateCode.data.ok) {
throw new Error(validateCode.success ? validateCode.data.message : validateCode.message)
}
cookie = validateCode.data.cookieverify_way 应优先使用服务端返回的实际值。不同账号可能返回不同的验证方式,例如 mobile_sms_verify 或 assist_mobile_sms_verify。biz_trace_id 也应在发送验证码和提交验证码时保持一致。
兼容性与稳定性说明
当前实现包含 Passport 专用的签名、a_bogus、环境指纹、Cookie 管理和 bd-ticket-guard 票据处理逻辑。这些内容不属于 Amagi 面向稳定数据接口的公共抽象,抖音也没有为这些 Web 内部接口提供稳定的第三方 API 契约。
使用时请注意:
- 抖音可能修改接口地址、请求字段、签名算法、Cookie 语义或风控规则;
- 同一账号、设备、网络环境下的可用验证方式可能不同;
- 获取二维码成功不代表后续轮询或登录一定成功;
confirmed、ok和logged_in等字段应结合实际返回结果判断,不应只根据 HTTP 或外层code判断;- 请妥善保管返回的登录 Cookie,不要写入日志、提交到代码仓库或暴露给不可信的第三方;
- 发生异常时可以启用 debug 日志辅助排查,但仍应避免记录完整 Cookie 或验证码。
如果需要稳定的抖音数据访问能力,请继续使用现有的抖音 Fetcher API。Passport 登录仅建议用于实验、开发验证和能够接受接口变化的场景。
最后更新于 2026-09-17