身份验证
除自描述的根路径外,每个请求都需要带上一个请求头。
Authorization: Bearer <your api key>
令牌在您的个人中心生成。每个账户最多十个,每个都可以单独吊销,因此某个令牌泄露时,删除它不会影响其他令牌。使用 API 需要付费套餐:没有付费套餐时,除 / 和 /v1/account 外的所有接口都会返回 403 plan_required。
应用也可以通过 OAuth 2.1 为您获取令牌:您登录后查看它申请的权限,然后点击“允许”。这类令牌放在同一个请求头中,用法完全相同。
为什么不用 ?key=
放在查询字符串中的密钥,会出现在您意想不到的地方:Web 服务器访问日志、浏览器历史记录、代理日志,以及响应中链接到的任何资源的 Referer 请求头。因此 API 不接受这种方式,并会返回 401 missing_key 予以说明。
主站上的旧版 ?export= URL 仍然接受 ?key=,因为多年前编写的脚本依赖它,取消支持会导致这些脚本失效。这是唯一接受它的地方,详见旧版导出 URL。
检查令牌是否可用
/v1/account 是成本最低的调用:它不消耗配额,即使账户没有套餐也能使用,因此既能回答“这个令牌是否有效”,也能回答“我有哪些权限”。
curl -H "Authorization: Bearer $KEY" https://api.publicwww.com/v1/account
{
"plan": "enterprise",
"plan_until": 1819461840,
"full_access": true,
"quota": {
"searches": { "limit": 300, "used": 12, "resets_at": 1787961600 },
"snippets": { "limit": 100, "used": 3, "resets_at": 1787961600 }
},
"limits": {
"disclosed_positions": 4294967295,
"max_per_page": 1000000,
"max_per_page_snippets": 10000
}
}
可能出现的错误
| 状态 | 错误码 | 含义 |
|---|---|---|
| 401 | missing_key | 缺少 Authorization: Bearer 请求头。查询字符串中的密钥不算数。 |
| 401 | invalid_key | 该令牌不对应任何账户。请检查是否混入了多余的换行符或引号。 |
| 403 | plan_required | 令牌本身没问题,但该账户没有付费套餐。 |
401 响应还会附带 WWW-Authenticate: Bearer 响应头,因此通用处理身份验证的 HTTP 客户端也能正确应对。
面向应用的 OAuth 2.1
代表他人工作的应用(助手、集成、托管服务)不应要求每位用户手动复制令牌,而应将用户引导至 PublicWWW:用户登录并批准该应用后,应用即可获得自己的令牌。该令牌与其他令牌一样以 Authorization: Bearer 发送,可访问整个 API 以及位于 https://api.publicwww.com/mcp 的 MCP 服务器,并受该账户的套餐、配额和速率限制约束。
| 项目 | 地址 |
|---|---|
| 授权服务器元数据(RFC 8414) | https://publicwww.com/.well-known/oauth-authorization-server |
| 受保护资源元数据(RFC 9728) | https://api.publicwww.com/.well-known/oauth-protected-resource |
| 授权端点 | https://publicwww.com/oauth/authorize |
| 令牌端点 | https://publicwww.com/oauth/token |
| 吊销端点(RFC 7009) | https://publicwww.com/oauth/revoke |
识别应用
无需注册客户端。client_id 就是应用所发布的一个小型 JSON 文档的 https URL,即客户端元数据文档(client metadata document)。每次有人连接时,PublicWWW 都会读取该文档,因此应用名称和回调地址始终是最新的,批准授权的用户也能看到是哪个主机发布了它们。
{
"client_id": "https://app.example.com/oauth/client.json",
"client_name": "Example App",
"redirect_uris": ["https://app.example.com/oauth/callback"],
"grant_types": ["authorization_code"],
"response_types": ["code"],
"token_endpoint_auth_method": "none"
}
-
文档中的
client_id必须与提供该文档的 URL 完全一致。文档通过 https 获取,URL 必须包含路径,且不跟随重定向;必须在 5 秒内响应,大小不超过 64 KB。 -
redirect_uris必须是 https 地址;如果应用运行在用户自己的电脑上,也可以是127.0.0.1、localhost或[::1]上的 http 地址,此时任意端口均可匹配。不接受myapp://之类的自定义协议。 -
所有应用都是公共客户端:无论文档中声明的
token_endpoint_auth_method是什么,令牌请求都不携带密钥。授权码改由 PKCE 保护。
授权流程
采用带 PKCE 的授权码模式,S256 是唯一支持的方法。将用户引导至授权端点:
https://publicwww.com/oauth/authorize
?response_type=code
&client_id=https%3A%2F%2Fapp.example.com%2Foauth%2Fclient.json
&redirect_uri=https%3A%2F%2Fapp.example.com%2Foauth%2Fcallback
&code_challenge=<BASE64URL(SHA-256(code_verifier))>
&code_challenge_method=S256
&state=<random>
如果用户尚未登录,需先使用邮件发送的一次性验证码登录;随后会看到应用名称、其文档所在的主机以及将要返回的地址,并点击“允许”或“取消”。返回 redirect_uri 时会带上 code、您的 state 以及 iss=https://publicwww.com(RFC 9207)。授权码有效期为十分钟,且只能使用一次。用它换取令牌:
curl https://publicwww.com/oauth/token \
-d grant_type=authorization_code \
-d code="$CODE" \
-d code_verifier="$VERIFIER" \
-d client_id=https://app.example.com/oauth/client.json \
-d redirect_uri=https://app.example.com/oauth/callback
{ "access_token": "<token>", "token_type": "Bearer", "scope": "mcp" }
scope 可以省略:只有一个作用域 mcp,它涵盖整个 API。resource(RFC 8707)同样可以省略;如果传入,其值应为 https://api.publicwww.com/mcp 或 https://api.publicwww.com。
令牌有效期
令牌在被吊销之前一直有效:没有过期时间,也没有刷新令牌。今天能用的集成,明天无需任何人干预也能继续使用。令牌只会在有意为之时被吊销:用户在个人中心断开该应用、应用自行吊销,或账户被删除。
curl https://publicwww.com/oauth/revoke \
-d token="$TOKEN" \
-d client_id=https://app.example.com/oauth/client.json
无论令牌是否存在,吊销端点始终返回 200。
OAuth 错误
| 环节 | 错误码 | 含义 |
|---|---|---|
| 授权 | 错误页面 | 无法读取 client_id 指向的文档,或文档中未列出 redirect_uri。此时不会将用户送回:未经验证的地址绝不跳转。 |
| 授权 | invalid_request | 缺少 code_challenge,或使用了 S256 以外的方法。 |
| 授权 | unsupported_response_type | 使用了 response_type=code 以外的值。 |
| 授权、令牌 | invalid_target | resource 不是本 API。 |
| 授权 | access_denied | 用户点击了“取消”。 |
| 令牌 | invalid_grant | 授权码未知、已使用、已过期或签发给了其他 client_id;或者 code_verifier 或 redirect_uri 不匹配。 |
| 令牌 | unsupported_grant_type | 使用了 authorization_code 以外的授权类型。 |
除错误页面外,授权错误会以 error、error_description、state 和 iss 参数返回到 redirect_uri;令牌错误则返回 400,并在 JSON 中包含同样的两个字段。