读取授权账号资料与权限
完成官方授权后读取账号资料,再核对用户实际授予的 scope;包含完整 HMAC-SHA256 请求签名代码。
← 返回平台功能接入准备
- 已通过当前企业开发者入驻与应用认证;官方入驻指引暂未开放个人申请,需营业执照、公函及一致的应用 ICP 主体。
- 拥有同一应用的 Client ID 和 App Secret,并通过对应 scope 申请;用户授权与应用获批是两项独立条件。
- 安装 Node.js 22;本页代码只从环境变量读自己的凭证,网站不会代收密钥或发送请求。
- 应用已获批 USER_INFO,目标用户也已同意该权限,已取得未过期 access_token;否则不能读取公开信息。
准备环境变量
示例值需要替换为自己的凭证或资源 ID。代码在本机或服务端运行;密钥不应放进公开网页。
BILIBILI_CLIENT_ID- 企业入驻、创建并审核应用后,在管理中心取得该应用 Client ID。
BILIBILI_APP_SECRET- 同一应用的 App Secret,只放在本机或受保护服务端,不放入网页源码。
BILIBILI_ACCESS_TOKEN- 目标 UP 主已同意该应用所需 scope 后,由服务端以 OAuth code 交换的有效令牌。
export BILIBILI_CLIENT_ID='replace_with_your_client_id'
export BILIBILI_APP_SECRET='replace_with_your_app_secret'
export BILIBILI_ACCESS_TOKEN='replace_with_your_user_access_token'以上 export 适用于 macOS / Linux 的终端。按调用步骤保存代码文件,再在同一终端执行。
调用步骤
- 01
管理中心配置应用回调域和 USER_INFO 权限。PC 授权入口为 https://account.bilibili.com/pc/account-pc/auth/oauth,携带 client_id、URL 编码后的 gourl、与会话绑定的随机 state;移动 H5 入口参考本页官方资料。
- 02
用户同意后,你自己的回调服务校验 state,并以 code、client_id、client_secret、grant_type=authorization_code 向 https://api.bilibili.com/x/account-oauth2/v1/token 发送 application/x-www-form-urlencoded 表单;官方 C# 示例同样使用表单。保存返回的令牌及有效期,勿将密钥放入前端。
- 03
设置下方同一应用的环境变量。先运行账号信息代码,再单独运行 scope 查询代码;两段均独立保存为 request.mjs,并用 node request.mjs 执行。
- 04
确认两次结果的 openid 属于同一应用下的同一授权用户;仅当 scopes 含目标权限时展示对应功能。应用新增权限后必须重新引导该用户授权。
获取当前授权用户资料
读取该令牌对应 UP 主的昵称、头像地址与 openid,无 UID 查询参数。
https://member.bilibili.com/arcopen/fn/user/account/info请求头
Acceptapplication/jsonContent-Typeapplication/jsonaccess-token${BILIBILI_ACCESS_TOKEN}x-bili-accesskeyid${BILIBILI_CLIENT_ID}x-bili-signature-version2.0x-bili-signature-methodHMAC-SHA256x-bili-content-md5d41d8cd98f00b204e9800998ecf8427ex-bili-timestamp运行时生成 Unix 秒时间戳x-bili-signature-nonce运行时生成唯一随机串Authorization运行时由下方完整代码计算 HMAC-SHA256
参数说明
参数表可左右滑动,查看完整说明。
| 字段 / 位置 | 类型 / 必填 | 说明 |
|---|---|---|
access-tokenHeader | string必填 | 当前 UP 主向同一应用授权后取得的 access_token;不是网页登录 Cookie,不加 Bearer 前缀。 |
x-bili-accesskeyidHeader | string必填 | 开放平台应用 client_id,必须与 app_secret 及令牌所属应用一致。 |
x-bili-content-md5Header | string必填 | 本页 GET 无请求体,使用空字符串的 MD5 小写十六进制 d41d8cd98f00b204e9800998ecf8427e。 |
x-bili-timestamp / x-bili-signature-nonceHeader | string必填 | Unix 秒时间戳及每次新生成的唯一随机串;时间戳偏离当前时间不能超过官方规定的 10 分钟。 |
x-bili-signature-method / x-bili-signature-versionHeader | string必填 | 固定 HMAC-SHA256 与 2.0。 |
AuthorizationHeader | string必填 | 将 x-bili- 头名按字典序排序,以 key:value 和 LF 连接,末尾无 LF;用 app_secret 做 HMAC-SHA256,结果为小写十六进制。 |
Accept / Content-TypeHeader | string必填 | 本例均为 application/json;GET 不发送 JSON body。 |
调用代码
替换示例 ID 与请求体内容后运行。
import { createHash, createHmac, randomUUID } from 'node:crypto';
const required = (name) => {
const value = process.env[name];
if (!value || value.includes('replace_with_')) throw new Error(`请设置自己的 ${name}`);
if (/[\r\n]/.test(value)) throw new Error(`${name} 不能包含换行`);
return value;
};
const clientId = required('BILIBILI_CLIENT_ID');
const secret = required('BILIBILI_APP_SECRET');
const token = required('BILIBILI_ACCESS_TOKEN');
const url = 'https://member.bilibili.com/arcopen/fn/user/account/info';
// 本例为 GET,无 body。空字符串的 MD5 仍需发送,不能省略或改成 {} 的 MD5。
const signingHeaders = {
'x-bili-accesskeyid': clientId,
'x-bili-content-md5': createHash('md5').update('', 'utf8').digest('hex'),
'x-bili-signature-method': 'HMAC-SHA256',
'x-bili-signature-nonce': randomUUID(),
'x-bili-signature-version': '2.0',
'x-bili-timestamp': String(Math.floor(Date.now() / 1000)),
};
// 只对 x-bili- 请求头排序;每行 key:value,以 LF 分隔,最后一行不追加换行。
const canonical = Object.keys(signingHeaders).sort()
.map((key) => `${key}:${signingHeaders[key]}`).join('\n');
const authorization = createHmac('sha256', Buffer.from(secret, 'utf8'))
.update(canonical, 'utf8').digest('hex');
const response = await fetch(url, {
method: 'GET', redirect: 'error', signal: AbortSignal.timeout(20000),
headers: { ...signingHeaders, 'access-token': token, Authorization: authorization,
Accept: 'application/json', 'Content-Type': 'application/json' },
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
let result;
try { result = JSON.parse(await response.text()); }
catch { throw new Error('平台未返回有效 JSON,检查服务状态及请求地址'); }
if (result.code !== 0) {
throw new Error(`业务错误 ${result.code}: ${result.message || ''}; request_id=${result.request_id || ''}`);
}
if (!result.data || typeof result.data !== 'object') throw new Error('响应缺少预期 data');
console.log(JSON.stringify(result.data, null, 2));
// 输出只来自该授权用户;生产系统应限制访问并按用户同意范围保存。
返回示例
按官方字段整理;示例昵称、头像地址及 openid 为说明值。face 需按官方要求自行缓存,不直接热链展示。 以下为结构示意,非本站实测结果。
{
"code": 0,
"message": "0",
"request_id": "example_request_id",
"data": {
"name": "演示用户",
"face": "https://i0.hdslb.com/bfs/face/example_avatar.jpg",
"openid": "example_openid_for_this_app"
}
}常见错误与排查
4002 / 4008 / 127002签名异常或请求体 MD5 不匹配。- 核对同一应用的 client_id 与 app_secret、全部六个 x-bili- 头、LF 分隔且末尾无换行;GET 应签空字符串,不要把 {} 当请求体。
4003 / 4004请求过期或重复请求。- 校准机器时钟、使用秒级时间戳,并为每次请求生成新 nonce,不要重复复制文档中的固定签名。
127001 / 127011令牌无效或用户未授权所需接口。- 确认令牌有效期、应用归属及用户已勾选的 scope;新增 scope 需重新引导授权。不要反复重试无效令牌。
127005 / 127006 / 127007 / 127305主体、应用、接口权限或白名单未通过。- 到管理中心核对认证及权限审批状态;官方白名单限制不能靠换账号 Cookie 解决。
127009 / 127306接口次数达到上限、繁忙或频率过高。- 停止紧密重试,缓存结果并按实际限额退避;大量使用需向平台运营确认配额,本文不杜撰统一 QPS。
调用注意
- 下方仅提供 Node.js 22 完整示例,使用内置 crypto 和 fetch。保存为 request.mjs,执行 node request.mjs;不提供缺少动态签名的伪 cURL。
- 所有 x-bili- 头参与签名;access-token、Accept、Content-Type 与 Authorization 不加入该签名串。HTTP 成功后仍须检查业务 code=0。
- 官方接口页未列按次价格或统一配额,需在应用实际开通时确认;本页仅完成协议与离线检查,未真实调用。
查询该用户已授予的 scope
返回用户对当前应用实际勾选的权限,不等于平台全部权限目录。
https://member.bilibili.com/arcopen/fn/user/account/scopes请求头
Acceptapplication/jsonContent-Typeapplication/jsonaccess-token${BILIBILI_ACCESS_TOKEN}x-bili-accesskeyid${BILIBILI_CLIENT_ID}x-bili-signature-version2.0x-bili-signature-methodHMAC-SHA256x-bili-content-md5d41d8cd98f00b204e9800998ecf8427ex-bili-timestamp运行时生成 Unix 秒时间戳x-bili-signature-nonce运行时生成唯一随机串Authorization运行时由下方完整代码计算 HMAC-SHA256
参数说明
参数表可左右滑动,查看完整说明。
| 字段 / 位置 | 类型 / 必填 | 说明 |
|---|---|---|
access-tokenHeader | string必填 | 当前 UP 主向同一应用授权后取得的 access_token;不是网页登录 Cookie,不加 Bearer 前缀。 |
x-bili-accesskeyidHeader | string必填 | 开放平台应用 client_id,必须与 app_secret 及令牌所属应用一致。 |
x-bili-content-md5Header | string必填 | 本页 GET 无请求体,使用空字符串的 MD5 小写十六进制 d41d8cd98f00b204e9800998ecf8427e。 |
x-bili-timestamp / x-bili-signature-nonceHeader | string必填 | Unix 秒时间戳及每次新生成的唯一随机串;时间戳偏离当前时间不能超过官方规定的 10 分钟。 |
x-bili-signature-method / x-bili-signature-versionHeader | string必填 | 固定 HMAC-SHA256 与 2.0。 |
AuthorizationHeader | string必填 | 将 x-bili- 头名按字典序排序,以 key:value 和 LF 连接,末尾无 LF;用 app_secret 做 HMAC-SHA256,结果为小写十六进制。 |
Accept / Content-TypeHeader | string必填 | 本例均为 application/json;GET 不发送 JSON body。 |
调用代码
替换示例 ID 与请求体内容后运行。
import { createHash, createHmac, randomUUID } from 'node:crypto';
const required = (name) => {
const value = process.env[name];
if (!value || value.includes('replace_with_')) throw new Error(`请设置自己的 ${name}`);
if (/[\r\n]/.test(value)) throw new Error(`${name} 不能包含换行`);
return value;
};
const clientId = required('BILIBILI_CLIENT_ID');
const secret = required('BILIBILI_APP_SECRET');
const token = required('BILIBILI_ACCESS_TOKEN');
const url = 'https://member.bilibili.com/arcopen/fn/user/account/scopes';
// 本例为 GET,无 body。空字符串的 MD5 仍需发送,不能省略或改成 {} 的 MD5。
const signingHeaders = {
'x-bili-accesskeyid': clientId,
'x-bili-content-md5': createHash('md5').update('', 'utf8').digest('hex'),
'x-bili-signature-method': 'HMAC-SHA256',
'x-bili-signature-nonce': randomUUID(),
'x-bili-signature-version': '2.0',
'x-bili-timestamp': String(Math.floor(Date.now() / 1000)),
};
// 只对 x-bili- 请求头排序;每行 key:value,以 LF 分隔,最后一行不追加换行。
const canonical = Object.keys(signingHeaders).sort()
.map((key) => `${key}:${signingHeaders[key]}`).join('\n');
const authorization = createHmac('sha256', Buffer.from(secret, 'utf8'))
.update(canonical, 'utf8').digest('hex');
const response = await fetch(url, {
method: 'GET', redirect: 'error', signal: AbortSignal.timeout(20000),
headers: { ...signingHeaders, 'access-token': token, Authorization: authorization,
Accept: 'application/json', 'Content-Type': 'application/json' },
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
let result;
try { result = JSON.parse(await response.text()); }
catch { throw new Error('平台未返回有效 JSON,检查服务状态及请求地址'); }
if (result.code !== 0) {
throw new Error(`业务错误 ${result.code}: ${result.message || ''}; request_id=${result.request_id || ''}`);
}
if (!result.data || typeof result.data !== 'object') throw new Error('响应缺少预期 data');
console.log(JSON.stringify(result.data, null, 2));
// 输出只来自该授权用户;生产系统应限制访问并按用户同意范围保存。
返回示例
scopes 示例仅表示本例说明的两项权限,并不表示所有授权用户都已授予 ARC_BASE;应逐次核对。 以下为结构示意,非本站实测结果。
{
"code": 0,
"message": "0",
"request_id": "example_request_id",
"data": {
"openid": "example_openid_for_this_app",
"scopes": [
"USER_INFO",
"ARC_BASE"
]
}
}常见错误与排查
4002 / 4008 / 127002签名异常或请求体 MD5 不匹配。- 核对同一应用的 client_id 与 app_secret、全部六个 x-bili- 头、LF 分隔且末尾无换行;GET 应签空字符串,不要把 {} 当请求体。
4003 / 4004请求过期或重复请求。- 校准机器时钟、使用秒级时间戳,并为每次请求生成新 nonce,不要重复复制文档中的固定签名。
127001 / 127011令牌无效或用户未授权所需接口。- 确认令牌有效期、应用归属及用户已勾选的 scope;新增 scope 需重新引导授权。不要反复重试无效令牌。
127005 / 127006 / 127007 / 127305主体、应用、接口权限或白名单未通过。- 到管理中心核对认证及权限审批状态;官方白名单限制不能靠换账号 Cookie 解决。
127009 / 127306接口次数达到上限、繁忙或频率过高。- 停止紧密重试,缓存结果并按实际限额退避;大量使用需向平台运营确认配额,本文不杜撰统一 QPS。
调用注意
- 下方仅提供 Node.js 22 完整示例,使用内置 crypto 和 fetch。保存为 request.mjs,执行 node request.mjs;不提供缺少动态签名的伪 cURL。
- 所有 x-bili- 头参与签名;access-token、Accept、Content-Type 与 Authorization 不加入该签名串。HTTP 成功后仍须检查业务 code=0。
- 官方接口页未列按次价格或统一配额,需在应用实际开通时确认;本页仅完成协议与离线检查,未真实调用。
注意事项
- 资源请求的公共签名版本固定 2.0;不能套用直播创作者服务中心的项目签名。
- 官方 expires_in 字段说明为 UTC 过期时间,不能照搬其他平台把它直接当有效时长相加;依官方返回管理续期,refresh_token 每个只能使用一次。
- 账号公开信息仍要求授权。openid 在开发者与应用维度唯一,不等同全站 UID;头像按官方要求自行缓存后使用。
核验来源
本站按官方资料整理本场景的必要调用步骤与代码,覆盖范围以本页列出的接口为准。官方资料用于追溯规范及查看变更。
- 01开发者入驻与主体认证核验日期 2026-10-15
- 02网页应用 OAuth 2.0 接入核验日期 2026-10-15
- 03账号授权、令牌获取与续期核验日期 2026-10-15
- 04官方 C# 示例与直播平台适用范围区分核验日期 2026-10-15
- 05获取已授权用户基础公开信息核验日期 2026-10-15
- 06接口公共签名 2.0 与业务状态码核验日期 2026-10-15
- 07官方 C# 公共签名实现核验日期 2026-10-15
- 08查询用户已授权权限列表核验日期 2026-10-15
