Skip to main content

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 Authorization header 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:

FieldTypeRequiredDescription
grant_typestring✅ YesMust be "password"
emailstring✅ YesF2 account email
passwordstring✅ YesF2 account password
client_idstring✅ YesProvided by SkyAgent
client_secretstring✅ YesProvided 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:

FieldTypeDescription
access_tokenstringToken dùng cho các API calls tiếp theo
token_typestringLuôn là "Bearer"
expires_innumberThời gian hết hạn (giây), thường ~28,000s (~7.8 hours)
refresh_tokenstringToken để refresh khi access_token hết hạn
scopestringPermission scope, thường là "public"
created_atnumberUnix 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:

  1. Search FlightsPOST /api/v1/services/booking/v1/tim-chuyen
  2. List BookingsGET /api/v1/services/booking/v1/danh-sach-ve
  3. Get AirportsGET /api/v1/current/airports

See related docs:

  • 02-GET-AIRPORTS.md - Get airports list
  • 03-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