Authentication - Xác Thực OAuth 2.0
API Endpoint: POST /oauth/token
📋 Overview
Xác thực bằng OAuth 2.0 Password Grant để lấy access token.
Flow:
Client App → POST /oauth/token → SkyAgent API
← access_token (valid 7-8 hours)
🔌 API Specification
Endpoint
POST {{base_url}}/oauth/token
Headers
{
"Content-Type": "application/json",
"Accept": "application/json"
}
⚠️ Important:
- NO
Authorizationheader required for this endpoint - Use base API URL (port 3000 in development)
Request Body
{
"grant_type": "password",
"email": "your-email@example.com",
"password": "your-password",
"client_id": "gSwj9376QaRBMFOgcV8mcPUDitZ_X_DsE1EqAlun7iQ",
"client_secret": "your-client-secret"
}
Fields:
| Field | Type | Required | Description |
|---|---|---|---|
grant_type | string | ✅ Yes | Must be "password" |
email | string | ✅ Yes | F2 account email |
password | string | ✅ Yes | F2 account password |
client_id | string | ✅ Yes | Provided by SkyAgent |
client_secret | string | ✅ Yes | Provided by SkyAgent |
✅ Success Response
Status: 200 OK
{
"access_token": "-w6m3raWt2vSTvCoy_dXuGCHHor9k5g5JE2uzDRJfy0",
"token_type": "Bearer",
"expires_in": 27972,
"refresh_token": "bRbPTOhLzNF_jrD_vkTfEsrSTPtl1xkN0ixIodjcXZ4",
"scope": "public",
"created_at": 1761059163
}
Fields:
| Field | Type | Description |
|---|---|---|
access_token | string | Token dùng cho các API calls tiếp theo |
token_type | string | Luôn là "Bearer" |
expires_in | number | Thời gian hết hạn (giây), thường ~28,000s (~7.8 hours) |
refresh_token | string | Token để refresh khi access_token hết hạn |
scope | string | Permission scope, thường là "public" |
created_at | number | Unix timestamp khi token được tạo |
❌ Error Responses
Invalid Credentials
Status: 401 Unauthorized
{
"error": "invalid_grant",
"error_description": "The provided authorization grant is invalid"
}
Cause: Email hoặc password sai
Invalid Client
Status: 401 Unauthorized
{
"error": "invalid_client",
"error_description": "Client authentication failed"
}
Cause: client_id hoặc client_secret sai
Missing Parameters
Status: 400 Bad Request
{
"error": "invalid_request",
"error_description": "The request is missing a required parameter"
}
Cause: Thiếu required field trong request body
💡 Example: cURL
curl -X POST {{base_url}}/oauth/token \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"grant_type": "password",
"email": "your-email@example.com",
"password": "your-password",
"client_id": "gSwj9376QaRBMFOgcV8mcPUDitZ_X_DsE1EqAlun7iQ",
"client_secret": "your-client-secret"
}'
Response:
{
"access_token": "-w6m3raWt2vSTvCoy_dXuGCHHor9k5g5JE2uzDRJfy0",
"token_type": "Bearer",
"expires_in": 27972,
"refresh_token": "bRbPTOhLzNF_jrD_vkTfEsrSTPtl1xkN0ixIodjcXZ4",
"scope": "public",
"created_at": 1761059163
}
🔐 Using Access Token
Tất cả API calls tiếp theo phải include token trong header:
Authorization: Bearer {access_token}
Example:
const headers = {
"Content-Type": "application/json",
Accept: "application/json",
Authorization: "Bearer " + accessToken,
};
⏰ Token Expiration
Token Lifetime: ~7-8 hours (27,000-28,000 seconds)
Check if Token Valid
const expiresIn = response.expires_in; // seconds
const expiryTime = new Date(Date.now() + expiresIn * 1000);
console.log("Token expires at:", expiryTime);
console.log("Valid for:", (expiresIn / 3600).toFixed(2), "hours");
Handle Expiration
Option 1: Re-authenticate when token expires
if (Date.now() >= tokenExpiryTime) {
accessToken = await authenticate();
}
Option 2: Use refresh_token (if supported)
// Refresh token endpoint (if available)
POST /oauth/token
{
"grant_type": "refresh_token",
"refresh_token": "bRbPTOhLzNF_jrD_vkTfEsrSTPtl1xkN0ixIodjcXZ4",
"client_id": "...",
"client_secret": "..."
}
🐛 Common Issues
Invalid Credentials (401)
Response:
{
"error": "invalid_grant",
"error_description": "The provided authorization grant is invalid"
}
Solution: Verify email and password are correct
Invalid Client (401)
Response:
{
"error": "invalid_client",
"error_description": "Client authentication failed"
}
Solution: Verify client_id and client_secret provided by SkyAgent
Missing Parameters (400)
Response:
{
"error": "invalid_request",
"error_description": "The request is missing a required parameter"
}
Solution: Ensure all required fields (grant_type, email, password, client_id, client_secret) are included
🔗 Next Steps
After authentication, you can:
- Search Flights →
POST /api/v1/services/booking/v1/tim-chuyen - List Bookings →
GET /api/v1/services/booking/v1/danh-sach-ve - Get Airports →
GET /api/v1/current/airports
See related docs:
02-GET-AIRPORTS.md- Get airports list03-SEARCH-FLIGHTS.md- Search flights with Socket.IO../manage-booking/01-LIST-BOOKINGS.md- List existing bookings
📝 Notes
- Token valid cho cả HTTP và Socket.IO connections
- Một token có thể dùng cho nhiều requests concurrent
- Token lifetime: ~7-8 hours (27,000-28,000 seconds)
- Lưu token an toàn - không log ra console trong production
- Không hardcode credentials - dùng environment variables