API参考
本文档提供 user.blym.top OAuth 2.0服务的完整API参考。
基础信息
| 项目 |
值 |
| 基础URL |
https://user.blym.top |
| 授权端点 |
/oauth/authorize.php |
| 令牌端点 |
/oauth/token.php |
| 用户信息端点 |
/api/userinfo.php |
| 令牌验证端点 |
/api/tokeninfo.php |
授权端点
端点信息
| 项目 |
值 |
| URL |
/oauth/authorize.php |
| 方法 |
GET |
| 内容类型 |
text/html |
请求参数
| 参数 |
类型 |
必填 |
说明 |
| client_id |
string |
是 |
客户端ID |
| redirect_uri |
string |
是 |
回调地址 |
| response_type |
string |
是 |
固定值 code |
| scope |
string |
否 |
请求的作用域 |
| state |
string |
推荐 |
CSRF防护状态值 |
| code_challenge |
string |
否 |
PKCE挑战码 |
| code_challenge_method |
string |
否 |
PKCE方法:S256/plain |
| nonce |
string |
否 |
OpenID Connect nonce |
请求示例
GET /oauth/authorize.php?client_id=client_abc123&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback&response_type=code&scope=openid%20profile%20email&state=xyz789
成功响应
重定向到回调地址:
HTTP/1.1 302 Found
Location: https://example.com/callback?code=a1b2c3d4e5f6&state=xyz789
错误响应
重定向到回调地址并附带错误参数:
HTTP/1.1 302 Found
Location: https://example.com/callback?error=access_denied&error_description=The+user+denied+the+authorization+request&state=xyz789
错误代码
| 错误代码 |
说明 |
| invalid_request |
请求缺少必要参数 |
| unauthorized_client |
客户端未授权 |
| access_denied |
用户拒绝授权 |
| unsupported_response_type |
不支持的response_type |
| invalid_scope |
请求的作用域无效 |
| server_error |
服务器内部错误 |
令牌端点
端点信息
| 项目 |
值 |
| URL |
/oauth/token.php |
| 方法 |
POST |
| 内容类型 |
application/x-www-form-urlencoded 或 application/json |
授权码模式
请求参数
| 参数 |
类型 |
必填 |
说明 |
| grant_type |
string |
是 |
固定值 authorization_code |
| code |
string |
是 |
授权码 |
| redirect_uri |
string |
是 |
回调地址 |
| client_id |
string |
是 |
客户端ID |
| client_secret |
string |
是* |
客户端密钥 |
| code_verifier |
string |
否 |
PKCE验证码 |
*公开客户端(使用PKCE)可不提供client_secret
请求示例
POST /oauth/token.php HTTP/1.1
grant_type=authorization_code&code=a1b2c3d4e5f6&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback&client_id=client_abc123&client_secret=secret_xyz789
成功响应
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token": "at_a1b2c3d4e5f6g7h8i9j0",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "rt_k1l2m3n4o5p6q7r8s9t0",
"scope": "openid profile email",
"id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
刷新令牌模式
请求参数
| 参数 |
类型 |
必填 |
说明 |
| grant_type |
string |
是 |
固定值 refresh_token |
| refresh_token |
string |
是 |
刷新令牌 |
| client_id |
string |
是 |
客户端ID |
| client_secret |
string |
是 |
客户端密钥 |
| scope |
string |
否 |
新的作用域(可缩小) |
请求示例
POST /oauth/token.php HTTP/1.1
grant_type=refresh_token&refresh_token=rt_k1l2m3n4o5p6q7r8s9t0&client_id=client_abc123&client_secret=secret_xyz789
成功响应
{
"access_token": "at_new_token_here",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "rt_new_refresh_token",
"scope": "openid profile email"
}
客户端凭证模式
请求参数
| 参数 |
类型 |
必填 |
说明 |
| grant_type |
string |
是 |
固定值 client_credentials |
| client_id |
string |
是 |
客户端ID |
| client_secret |
string |
是 |
客户端密钥 |
| scope |
string |
否 |
请求的作用域 |
请求示例
POST /oauth/token.php HTTP/1.1
grant_type=client_credentials&client_id=client_abc123&client_secret=secret_xyz789&scope=read
错误响应
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "invalid_grant",
"error_description": "Authorization code has expired"
}
错误代码
| 错误代码 |
HTTP状态码 |
说明 |
| invalid_request |
400 |
请求缺少必要参数 |
| invalid_client |
401 |
客户端认证失败 |
| invalid_grant |
400 |
授权码/刷新令牌无效 |
| unauthorized_client |
400 |
客户端未授权 |
| unsupported_grant_type |
400 |
不支持的授权类型 |
| invalid_scope |
400 |
请求的作用域无效 |
用户信息端点
端点信息
| 项目 |
值 |
| URL |
/api/userinfo.php |
| 方法 |
GET |
| 认证 |
Bearer Token |
请求头
Authorization: Bearer {access_token}
请求示例
GET /api/userinfo.php HTTP/1.1
成功响应
HTTP/1.1 200 OK
Content-Type: application/json
{
"sub": "123",
"name": "张三",
"preferred_username": "zhangsan",
"email": "zhangsan@example.com",
"email_verified": true,
"client_id": "client_abc123",
"scope": "openid profile email"
}
响应字段说明
| 字段 |
类型 |
说明 |
条件 |
| sub |
string |
用户唯一标识 |
始终返回 |
| name |
string |
用户显示名称 |
profile作用域 |
| preferred_username |
string |
用户名 |
profile作用域 |
| email |
string |
用户邮箱 |
email作用域 |
| email_verified |
boolean |
邮箱是否验证 |
email作用域 |
| client_id |
string |
客户端ID |
始终返回 |
| scope |
string |
授予的作用域 |
始终返回 |
错误响应
HTTP/1.1 401 Unauthorized
Content-Type: application/json
WWW-Authenticate: Bearer error="invalid_token", error_description="Invalid or expired access token"
{
"error": "invalid_token",
"error_description": "Invalid or expired access token"
}
令牌验证端点
端点信息
| 项目 |
值 |
| URL |
/api/tokeninfo.php |
| 方法 |
GET |
| 认证 |
Bearer Token |
请求示例
GET /api/tokeninfo.php HTTP/1.1
成功响应
HTTP/1.1 200 OK
Content-Type: application/json
{
"active": true,
"client_id": "client_abc123",
"user_id": "123",
"scope": "openid profile email",
"exp": 1234567890,
"iat": 1234563290,
"token_type": "Bearer",
"username": "zhangsan",
"email": "zhangsan@example.com"
}
无效令牌响应
HTTP/1.1 200 OK
Content-Type: application/json
{
"active": false
}
作用域说明
| 作用域 |
说明 |
用户信息端点返回 |
| openid |
OpenID Connect基本身份 |
sub |
| profile |
用户基本资料 |
name, preferred_username |
| email |
用户邮箱 |
email, email_verified |
| read |
读取用户数据 |
根据API定义 |
| write |
写入用户数据 |
根据API定义 |
| admin |
管理员权限 |
根据API定义 |
速率限制
| 端点 |
限制 |
| /oauth/token.php |
100次/分钟/IP |
| /api/userinfo.php |
1000次/小时/令牌 |
超过限制将返回:
HTTP/1.1 429 Too Many Requests
{
"error": "too_many_requests",
"error_description": "Rate limit exceeded"
}
SDK示例
PHP
<?php
class OAuthClient {
private $clientId;
private $clientSecret;
private $redirectUri;
private $baseUrl = 'https://user.blym.top';
public function __construct($clientId, $clientSecret, $redirectUri) {
$this->clientId = $clientId;
$this->clientSecret = $clientSecret;
$this->redirectUri = $redirectUri;
}
public function getAuthorizationUrl($state, $scope = 'openid profile email') {
$params = http_build_query([
'client_id' => $this->clientId,
'redirect_uri' => $this->redirectUri,
'response_type' => 'code',
'scope' => $scope,
'state' => $state
]);
return $this->baseUrl . '/oauth/authorize.php?' . $params;
}
public function getAccessToken($code) {
$ch = curl_init($this->baseUrl . '/oauth/token.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
'grant_type' => 'authorization_code',
'code' => $code,
'redirect_uri' => $this->redirectUri,
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
public function getUserInfo($accessToken) {
$ch = curl_init($this->baseUrl . '/api/userinfo.php');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $accessToken
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
}
$client = new OAuthClient(
'your_client_id',
'your_client_secret',
'https://your-app.com/callback'
);
$authUrl = $client->getAuthorizationUrl(uniqid());
$tokens = $client->getAccessToken($_GET['code']);
$userInfo = $client->getUserInfo($tokens['access_token']);
?>
JavaScript
class OAuthClient {
constructor(clientId, clientSecret, redirectUri) {
this.clientId = clientId;
this.clientSecret = clientSecret;
this.redirectUri = redirectUri;
this.baseUrl = 'https://user.blym.top';
}
getAuthorizationUrl(state, scope = 'openid profile email') {
const params = new URLSearchParams({
client_id: this.clientId,
redirect_uri: this.redirectUri,
response_type: 'code',
scope: scope,
state: state
});
return `${this.baseUrl}/oauth/authorize.php?${params}`;
}
async getAccessToken(code) {
const response = await fetch(`${this.baseUrl}/oauth/token.php`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code: code,
redirect_uri: this.redirectUri,
client_id: this.clientId,
client_secret: this.clientSecret
})
});
return response.json();
}
async getUserInfo(accessToken) {
const response = await fetch(`${this.baseUrl}/api/userinfo.php`, {
headers: { 'Authorization': `Bearer ${accessToken}` }
});
return response.json();
}
}