Documentation Index
Fetch the complete documentation index at: https://docs.aihubmix.com/llms.txt
Use this file to discover all available pages before exploring further.
Aviso de seguridad importante
Principio de seguridad ante todo: al desarrollar y desplegar aplicaciones de terceros, la seguridad es la consideración más importante. Debes seguir estrictamente los principios de seguridad expuestos a continuación para garantizar la seguridad de los datos de los usuarios y del proceso de autorización.
- Nunca expongas
client_secret en el código JavaScript del frontend
- El intercambio del código de autorización OAuth por el token debe gestionarse en el servidor
- Todo acceso a recursos protegidos del usuario debe pasar por un proxy de API en el backend
- Toda comunicación OAuth debe protegerse mediante HTTPS
¡Violar cualquiera de los principios de seguridad anteriores puede provocar vulnerabilidades de seguridad graves!
📋 Índice
- Descripción general
- Primeros pasos
- Flujo de autorización OAuth2
- Referencia de la API
- SDK y ejemplos de código
- Buenas prácticas de seguridad
- Preguntas frecuentes
- Soporte técnico
Descripción general
Ofrecemos una API abierta basada en el estándar OAuth2 que permite a las aplicaciones de terceros acceder de forma segura a la información básica de los usuarios y al saldo de su cuenta. A través de nuestro servicio OAuth2, tu aplicación puede:
- 🚀 Inicio de sesión con un clic: los usuarios no necesitan registrarse de nuevo; el inicio de sesión concede automáticamente la autorización, proporcionando una experiencia verdaderamente fluida
- 👤 Obtener información del usuario: acceder al perfil básico de los usuarios (nombre de usuario, correo electrónico, etc.)
- 💰 Ver el saldo de la cuenta: obtener el saldo de la cuenta del usuario en tiempo real
- 🔄 Redirección a recarga: guía al usuario a nuestra página de recarga para recargar su cuenta
- 🔐 Renovación automática de tokens: mecanismo integrado de refresh token para una renovación sin interrupciones, mejorando la experiencia del usuario
Primeros pasos
1. Registra una cuenta de desarrollador
Primero, debes registrar una cuenta de desarrollador en nuestro sistema.
2. Crea una aplicación OAuth
Crea tu aplicación OAuth en la consola de desarrolladores:
curl -X POST https://api.aihubmix.com/api/oauth_apps \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_DEVELOPER_TOKEN" \
-d '{
"name": "My Third-party App",
"description": "App description",
"redirect_uri": "https://yourapp.com/oauth/callback"
}'
Ejemplo de respuesta:
{
"success": true,
"message": "Application created successfully",
"data": {
"id": 1,
"name": "My Third-party App",
"client_id": "client_abc123def456...",
"client_secret": "secret_xyz789uvw012...",
"redirect_uri": "https://yourapp.com/oauth/callback",
"created_time": 1640995200
}
}
Aviso de seguridad importante:
- client_id puede utilizarse en el frontend (información pública)
client_secret solo puede utilizarse del lado del servidor y nunca debe exponerse al navegador
- Almacena client_secret en variables de entorno; no lo dejes en duro en el código
3. Configura el Redirect URI
Asegúrate de que tu URI de redirección cumpla los siguientes requisitos:
- Utilice el protocolo HTTPS (en producción)
- Apunte a un endpoint de tu servidor (no a una página de frontend)
- El dominio esté registrado y sea accesible
- La ruta sea específica del endpoint de API que gestiona la callback
Flujo de autorización OAuth2
Diagrama de flujo seguro
Instrucciones paso a paso
Paso 1: Guía al usuario para que autorice
Añade un botón de inicio de sesión en tu página de frontend. Al hacer clic, redirige al endpoint de autorización del lado del servidor:
Frontend code - only responsible for redirecting
function startLogin() {
// Redirect to your server-side authorization handler
window.location.href = '/auth/oauth/start';
}
Paso 2: Manejador de autorización en el servidor
Implementa el manejador de autorización en tu servidor:
app.get('/auth/oauth/start', (req, res) => {
// Generate and store state parameter
const state = generateSecureRandomString();
req.session.oauth_state = state;
// Build authorization URL
const authUrl = new URL('https://your-domain.com/api/oauth2/authorize');
authUrl.searchParams.append('client_id', process.env.OAUTH_CLIENT_ID);
authUrl.searchParams.append('redirect_uri', process.env.OAUTH_REDIRECT_URI);
authUrl.searchParams.append('response_type', 'code');
authUrl.searchParams.append('scope', 'profile balance');
authUrl.searchParams.append('state', state);
authUrl.searchParams.append('auto_authorize', 'true'); // One-click login
// Redirect to authorization server
res.redirect(authUrl.toString());
});
Paso 3: Gestionar la callback de autorización (del lado del servidor)
Server-side authorization callback handler
app.get('/oauth/callback', async (req, res) => {
const { code, state, error } = req.query;
// Error handling
if (error) {
return res.redirect(`/?error=${encodeURIComponent(error)}`);
}
// Parameter validation
if (!code || !state) {
return res.redirect('/?error=missing_parameters');
}
// Validate state parameter (prevent CSRF attacks)
if (state !== req.session.oauth_state) {
return res.redirect('/?error=invalid_state');
}
try {
// Exchange authorization code for access token (server-side)
const tokenResponse = await fetch('https://your-domain.com/api/oauth2/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code: code,
redirect_uri: process.env.OAUTH_REDIRECT_URI,
client_id: process.env.OAUTH_CLIENT_ID,
client_secret: process.env.OAUTH_CLIENT_SECRET // Server-side only
})
});
const tokenData = await tokenResponse.json();
if (!tokenResponse.ok) {
throw new Error(tokenData.error || 'Token exchange failed');
}
// Securely store token (server session or database)
req.session.access_token = tokenData.access_token;
req.session.refresh_token = tokenData.refresh_token;
req.session.token_expires_at = Date.now() + (tokenData.expires_in * 1000);
// Clean up temporary state
delete req.session.oauth_state;
// Redirect to frontend page
res.redirect('/?login=success');
} catch (error) {
console.error('OAuth callback error:', error);
res.redirect(`/?error=server_error`);
}
});
Frontend fetches user info via API proxy
async function loadUserInfo() {
try {
const response = await fetch('/api/user/info');
if (!response.ok) {
throw new Error('Failed to fetch user info');
}
const userInfo = await response.json();
displayUserInfo(userInfo);
} catch (error) {
console.error('Failed to load user info:', error);
showLoginButton();
}
}
app.get('/api/user/info', async (req, res) => {
const accessToken = req.session.access_token;
if (!accessToken) {
return res.status(401).json({ error: 'Not authenticated' });
}
try {
// Proxy request to OAuth server
const response = await fetch('https://your-domain.com/api/oauth2/userinfo', {
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
if (!response.ok) {
throw new Error('User info request failed');
}
const userInfo = await response.json();
res.json(userInfo);
} catch (error) {
console.error('User info proxy error:', error);
res.status(500).json({ error: 'Server error' });
}
});
Referencia de la API
1. Endpoint de autorización
GET /api/oauth2/authorize
Guía al usuario a través de la autorización OAuth2.
Parámetros:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|
client_id | string | Sí | ID de cliente de la aplicación (puede usarse en el frontend) |
redirect_uri | string | Sí | URI de callback tras la autorización (debe apuntar al endpoint del servidor) |
response_type | string | Sí | Fijo: code |
scope | string | No | Ámbito, separado por espacios |
state | string | Sí | Cadena aleatoria para prevenir ataques CSRF (generada en el servidor) |
auto_authorize | string | No | Establecer a true para activar la autorización automática |
Requisitos de seguridad:
redirect_uri debe coincidir exactamente con la dirección registrada
state debe ser una cadena aleatoria generada en el servidor
- Se debe usar HTTPS (en producción)
Explicación de los scopes:
profile: Acceso a la información básica del usuario (nombre de usuario, correo electrónico)
balance: Acceso al saldo de la cuenta del usuario
2. Endpoint del token
POST /api/oauth2/token
Aviso de seguridad: ¡este endpoint solo puede llamarse desde el lado del servidor, nunca desde el frontend!
Se utiliza en dos escenarios:
- Intercambiar el código de autorización por un access token
- Usar el refresh token para obtener un nuevo access token
Parámetros para la concesión por código de autorización:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|
grant_type | string | Sí | Fijo: authorization_code |
code | string | Sí | Código de autorización |
redirect_uri | string | Sí | Debe coincidir con la URI usada en la autorización |
client_id | string | Sí | ID de cliente de la aplicación |
client_secret | string | Sí | Secreto de cliente de la aplicación (solo del lado del servidor) |
Parámetros para la concesión por refresh token:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|
grant_type | string | Sí | Fijo: refresh_token |
refresh_token | string | Sí | Refresh token |
client_id | string | Sí | ID de cliente de la aplicación |
client_secret | string | Sí | Secreto de cliente de la aplicación (solo del lado del servidor) |
Ejemplo de respuesta:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 7200,
"refresh_token": "refresh_abc123def456...",
"scope": "profile balance"
}
GET /api/oauth2/userinfo
Obtén la información básica del usuario y el saldo de su cuenta.
Cabecera de la solicitud:
Authorization: Bearer {access_token}
Ejemplo de respuesta:
{
"id": 12345,
"username": "user123",
"email": "user@example.com",
"quota": 1000000,
"used_quota": 250000,
"balance_formatted": "750.00",
"created_time": 1640995200,
"status": 1
}
SDK y ejemplos de código
SDK de JavaScript
Ofrecemos un SDK completo de JavaScript que puedes utilizar directamente:
<!DOCTYPE html>
<html>
<head>
<title>Third-party App Example</title>
<style>
.container { max-width: 800px; margin: 0 auto; padding: 20px; }
.user-info { background: #f5f5f5; padding: 20px; border-radius: 8px; margin: 20px 0; }
.login-section { text-align: center; padding: 40px; }
.btn { padding: 12px 24px; border: none; border-radius: 6px; cursor: pointer; font-size: 16px; }
.btn-primary { background: #007bff; color: white; }
.btn-success { background: #28a745; color: white; }
.btn-secondary { background: #6c757d; color: white; }
.hidden { display: none; }
</style>
</head>
<body>
<div class="container">
<h1>我的第三方应用</h1>
<!-- Loading status -->
<div id="loading">
<p>Checking login status...</p>
</div>
<!-- Logged-in user info -->
<div id="user-info" class="user-info hidden">
<h2>Welcome back!</h2>
<p><strong>Username:</strong> <span id="username"></span></p>
<p><strong>Email:</strong> <span id="email"></span></p>
<p><strong>Account Balance:</strong> <span id="balance"></span></p>
<div style="margin-top: 20px;">
<button class="btn btn-success" onclick="refreshBalance()">Refresh Balance</button>
<button class="btn btn-primary" onclick="goToTopup()">Top Up Account</button>
<button class="btn btn-secondary" onclick="logout()">Log Out</button>
</div>
</div>
<!-- Not logged in status -->
<div id="login-section" class="login-section hidden">
<h2>Please log in to view account info</h2>
<p>Use one-click login for quick access to your account</p>
<button class="btn btn-primary" onclick="oneClickLogin()">
🚀 One-click Login
</button>
</div>
</div>
<script>
// OAuth configuration
const OAUTH_CONFIG = {
authServer: 'https://your-domain.com',
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET', // 生产环境应该在后端处理
redirectUri: window.location.origin + '/oauth/callback.html',
scope: 'profile balance'
};
class OAuthManager {
constructor() {
this.accessToken = localStorage.getItem('oauth_access_token');
this.refreshToken = localStorage.getItem('oauth_refresh_token');
this.tokenExpiresAt = localStorage.getItem('oauth_token_expires_at');
this.isRefreshing = false; // 防止并发刷新
this.init();
}
async init() {
// 检查URL中是否有授权码
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
const state = urlParams.get('state');
if (code) {
await this.handleAuthCallback(code, state);
// 清理URL
window.history.replaceState({}, document.title, window.location.pathname);
} else if (this.accessToken) {
try {
// 检查token是否过期,如果过期尝试刷新
if (this.isTokenExpired()) {
await this.refreshTokenIfNeeded();
}
await this.fetchUserInfo();
this.showUserInfo();
} catch (error) {
console.log('Token可能已过期或无效,需要重新登录');
this.clearTokens();
this.showLoginSection();
}
} else {
this.showLoginSection();
}
document.getElementById('loading').classList.add('hidden');
}
// Check if access token is expired
isTokenExpired() {
if (!this.tokenExpiresAt) return false;
const expiryTime = parseInt(this.tokenExpiresAt);
const bufferTime = 5 * 60 * 1000; // 5 minutes buffer
return Date.now() > (expiryTime - bufferTime);
}
// Automatically refresh token
async refreshTokenIfNeeded() {
if (!this.refreshToken || this.isRefreshing) {
return false;
}
this.isRefreshing = true;
try {
const response = await fetch(`${OAUTH_CONFIG.authServer}/api/oauth2/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: this.refreshToken,
client_id: OAUTH_CONFIG.clientId,
client_secret: OAUTH_CONFIG.clientSecret,
})
});
if (response.ok) {
const tokenData = await response.json();
this.updateTokens(tokenData);
return true;
} else {
throw new Error('Token refresh failed');
}
} catch (error) {
console.error('Failed to refresh token:', error);
this.clearTokens();
return false;
} finally {
this.isRefreshing = false;
}
}
// Update token info
updateTokens(tokenData) {
this.accessToken = tokenData.access_token;
this.refreshToken = tokenData.refresh_token;
this.tokenExpiresAt = Date.now() + (tokenData.expires_in * 1000);
localStorage.setItem('oauth_access_token', this.accessToken);
localStorage.setItem('oauth_refresh_token', this.refreshToken);
localStorage.setItem('oauth_token_expires_at', this.tokenExpiresAt.toString());
}
oneClickLogin() {
const state = this.generateState();
localStorage.setItem('oauth_state', state);
const authUrl = `${OAUTH_CONFIG.authServer}/api/oauth2/authorize?` +
`client_id=${OAUTH_CONFIG.clientId}&` +
`redirect_uri=${encodeURIComponent(OAUTH_CONFIG.redirectUri)}&` +
`response_type=code&` +
`scope=${encodeURIComponent(OAUTH_CONFIG.scope)}&` +
`state=${state}&` +
`auto_authorize=true`; // Enable auto-authorization for true one-click login
// Open authorization page in popup
const popup = window.open(authUrl, 'oauth_login', 'width=500,height=600,scrollbars=yes');
// Listen for popup close
const checkClosed = setInterval(() => {
if (popup.closed) {
clearInterval(checkClosed);
// 检查是否获得了授权
setTimeout(() => this.init(), 1000);
}
}, 1000);
}
async handleAuthCallback(code, state) {
const savedState = localStorage.getItem('oauth_state');
if (state !== savedState) {
console.error('State parameter mismatch');
return;
}
try {
const response = await fetch(`${OAUTH_CONFIG.authServer}/api/oauth2/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code: code,
client_id: OAUTH_CONFIG.clientId,
client_secret: OAUTH_CONFIG.clientSecret,
redirect_uri: OAUTH_CONFIG.redirectUri
})
});
const tokenData = await response.json();
if (tokenData.access_token) {
this.updateTokens(tokenData);
localStorage.removeItem('oauth_state');
await this.fetchUserInfo();
this.showUserInfo();
}
} catch (error) {
console.error('获取访问令牌失败:', error);
}
}
// API request method with auto-refresh
async apiRequest(url, options = {}) {
// Check and refresh token if needed
if (this.isTokenExpired()) {
const refreshed = await this.refreshTokenIfNeeded();
if (!refreshed) {
throw new Error('Unable to refresh token');
}
}
const headers = {
'Authorization': `Bearer ${this.accessToken}`,
...options.headers
};
const response = await fetch(url, {
...options,
headers
});
// If a 401 error is received, try to refresh token and retry once
if (response.status === 401 && !options._retry) {
const refreshed = await this.refreshTokenIfNeeded();
if (refreshed) {
return this.apiRequest(url, { ...options, _retry: true });
}
}
return response;
}
async fetchUserInfo() {
const response = await this.apiRequest(`${OAUTH_CONFIG.authServer}/api/oauth2/userinfo`);
if (!response.ok) {
throw new Error('Failed to get user info');
}
this.userInfo = await response.json();
}
showUserInfo() {
document.getElementById('username').textContent = this.userInfo.username;
document.getElementById('email').textContent = this.userInfo.email;
document.getElementById('balance').textContent = this.userInfo.balance_formatted;
document.getElementById('user-info').classList.remove('hidden');
document.getElementById('login-section').classList.add('hidden');
}
showLoginSection() {
document.getElementById('user-info').classList.add('hidden');
document.getElementById('login-section').classList.remove('hidden');
}
async refreshBalance() {
try {
await this.fetchUserInfo();
document.getElementById('balance').textContent = this.userInfo.balance_formatted;
alert('Balance updated');
} catch (error) {
alert('Refresh failed, please log in again');
this.clearTokens();
this.showLoginSection();
}
}
async goToTopup() {
try {
const response = await this.apiRequest(`${OAUTH_CONFIG.authServer}/api/oauth2/topup`);
const data = await response.json();
if (data.topup_url) {
window.open(data.topup_url, '_blank');
}
} catch (error) {
console.error('Failed to get top-up link:', error);
}
}
logout() {
this.clearTokens();
this.showLoginSection();
}
clearTokens() {
this.accessToken = null;
this.refreshToken = null;
this.tokenExpiresAt = null;
this.userInfo = null;
localStorage.removeItem('oauth_access_token');
localStorage.removeItem('oauth_refresh_token');
localStorage.removeItem('oauth_token_expires_at');
}
generateState() {
return Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15);
}
}
// 全局函数
let oauthManager;
function oneClickLogin() {
oauthManager.oneClickLogin();
}
function refreshBalance() {
oauthManager.refreshBalance();
}
function goToTopup() {
oauthManager.goToTopup();
}
function logout() {
oauthManager.logout();
}
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', () => {
oauthManager = new OAuthManager();
});
</script>
</body>
</html>
Página de callback de OAuth
Crea un archivo /oauth/callback.html:
<!DOCTYPE html>
<html>
<head>
<title>Logging in...</title>
<style>
body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }
.loading { color: #666; }
.error { color: #dc3545; }
</style>
</head>
<body>
<h2>Logging in, please wait...</h2>
<div id="status" class="loading">Verifying authorization information...</div>
<script>
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
const state = urlParams.get('state');
const error = urlParams.get('error');
if (error) {
document.getElementById('status').innerHTML =
`<div class="error">Authorization failed: ${error}</div>`;
setTimeout(() => {
if (window.opener) {
window.close();
} else {
window.location.href = '/';
}
}, 3000);
} else if (code) {
if (window.opener) {
// 如果是弹窗,关闭并让父窗口处理
window.opener.location.href =
window.opener.location.pathname + `?code=${code}&state=${state}`;
window.close();
} else {
// 如果不是弹窗,重定向到主页面
window.location.href = `/?code=${code}&state=${state}`;
}
} else {
document.getElementById('status').innerHTML =
'<div class="error">No valid authorization information received</div>';
setTimeout(() => {
window.location.href = '/';
}, 3000);
}
</script>
</body>
</html>
Ejemplo de backend en Node.js
Para mayor seguridad, se recomienda gestionar client_secret en el backend:
const express = require('express');
const cors = require('cors');
const fetch = require('node-fetch');
const app = express();
app.use(cors());
app.use(express.json());
const OAUTH_CONFIG = {
authServer: 'https://your-domain.com',
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET'
};
// Backend handles token exchange
app.post('/api/oauth/exchange-token', async (req, res) => {
const { code, redirectUri, state } = req.body;
try {
const response = await fetch(`${OAUTH_CONFIG.authServer}/api/oauth2/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code: code,
client_id: OAUTH_CONFIG.clientId,
client_secret: OAUTH_CONFIG.clientSecret,
redirect_uri: redirectUri
})
});
const tokenData = await response.json();
if (response.ok) {
res.json(tokenData);
} else {
res.status(400).json(tokenData);
}
} catch (error) {
res.status(500).json({ error: 'Token exchange failed' });
}
});
// Refresh token endpoint
app.post('/api/oauth/refresh-token', async (req, res) => {
const { refreshToken } = req.body;
if (!refreshToken) {
return res.status(400).json({ error: 'Missing refresh token' });
}
try {
const response = await fetch(`${OAUTH_CONFIG.authServer}/api/oauth2/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: OAUTH_CONFIG.clientId,
client_secret: OAUTH_CONFIG.clientSecret,
})
});
const tokenData = await response.json();
if (response.ok) {
res.json(tokenData);
} else {
res.status(400).json(tokenData);
}
} catch (error) {
res.status(500).json({ error: 'Token refresh failed' });
}
});
// Proxy user info request (with auto-refresh)
app.get('/api/oauth/userinfo', async (req, res) => {
const authHeader = req.headers.authorization;
if (!authHeader) {
return res.status(401).json({ error: 'Missing authorization header' });
}
try {
const response = await fetch(`${OAUTH_CONFIG.authServer}/api/oauth2/userinfo`, {
headers: {
'Authorization': authHeader
}
});
const userData = await response.json();
if (response.ok) {
res.json(userData);
} else {
res.status(response.status).json(userData);
}
} catch (error) {
res.status(500).json({ error: 'Failed to fetch user info' });
}
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
Buenas prácticas de seguridad
1. Protección del client secret
- ✅ Recomendado: Almacena
client_secret en el servidor backend
- ❌ Evitar: Exponer
client_secret en JavaScript del frontend
2. Validación del parámetro state
// Generate random state
const state = crypto.randomBytes(16).toString('hex');
localStorage.setItem('oauth_state', state);
// Validate state
const savedState = localStorage.getItem('oauth_state');
if (receivedState !== savedState) {
throw new Error('CSRF attack detected');
}
3. Uso de HTTPS
- Debe usarse
HTTPS en producción
- El URI de callback debe usar
HTTPS
- Todas las solicitudes a la API usan
HTTPS
4. Almacenamiento seguro de tokens
// Set token expiry time
const expiryTime = Date.now() + (tokenData.expires_in * 1000);
localStorage.setItem('oauth_token_expiry', expiryTime);
// Check if token is expired
function isTokenExpired() {
const expiry = localStorage.getItem('oauth_token_expiry');
return !expiry || Date.now() > parseInt(expiry);
}
5. Manejo de errores
try {
const response = await fetch('/api/oauth2/userinfo', {
headers: { 'Authorization': `Bearer ${token}` }
});
if (!response.ok) {
if (response.status === 401) {
// Token expired, need to re-login
clearToken();
showLoginSection();
} else {
throw new Error(`HTTP ${response.status}`);
}
}
const userInfo = await response.json();
return userInfo;
} catch (error) {
console.error('API request failed:', error);
// Handle network errors etc.
}
Preguntas frecuentes
P1: ¿Cómo conseguir una verdadera experiencia de inicio de sesión con un clic?
R: Solo tienes que añadir el parámetro auto_authorize=true a la URL de autorización. Después de que el usuario inicie sesión, la autorización se concederá automáticamente, sin ningún paso adicional de confirmación:
const authUrl = 'https://your-domain.com/api/oauth2/authorize?' +
'client_id=YOUR_CLIENT_ID&' +
'auto_authorize=true&' + // Key parameter
'...other parameters';
P2: ¿Los tokens se renuevan automáticamente?
R: Sí, nuestro SDK incorpora la renovación automática de tokens:
- Access token: válido durante 2 horas, se renueva automáticamente 5 minutos antes de su expiración
- Refresh token: válido durante 30 días, se utiliza para obtener nuevos access tokens
- Renovación sin interrupciones: Todas las llamadas a la API comprobarán y renovarán automáticamente los tokens caducados
- Reintento en caso de fallo: Si la API devuelve un error 401, intentará renovar automáticamente el token y reintentar
// The SDK will handle token refresh automatically, no manual handling needed
const userInfo = await oauthManager.fetchUserInfo(); // token auto-refresh
Solo si el refresh token también caduca el usuario deberá iniciar sesión de nuevo.
R: Según el alcance autorizado, puedes obtener:
- Scope
profile: nombre de usuario, correo electrónico
- Scope
balance: información del saldo de la cuenta
P4: ¿Cómo puedo probar la integración OAuth?
R:
- Usa
HTTP localhost en desarrollo para realizar pruebas
- Utiliza nuestras herramientas de prueba proporcionadas para verificar el flujo de autorización
- Comprueba las solicitudes de red en las herramientas de desarrollador de tu navegador
P5: ¿Qué lenguajes de programación se admiten?
R: Nuestra API OAuth2 es estándar y admite todos los lenguajes de programación principales:
- JavaScript/Node.js
- Python
- PHP
- Java
- C#/.NET
- Go
- Ruby
P6: ¿Cómo puede un usuario revocar la autorización?
R: Los usuarios pueden revocar la autorización de aplicaciones de terceros en la página Centro de usuarios > Gestión de autorizaciones.
Última actualización: 2026-06-01