Authentication Module
Xác thực và quản lý phiên làm việc với SkyAgent API.
📋 Overview
Module xác thực bao gồm 2 APIs chính:
- OAuth Token - Đăng nhập và lấy access token
- Get Profile - Lấy thông tin user & agency
🔄 Authentication Flow
📚 APIs
1. OAuth Token
Doc: 01-AUTHENTICATION.md
Endpoint: POST /oauth/token
Purpose: Login và lấy access token
Input:
{
"grant_type": "password",
"email": "user@example.com",
"password": "password",
"client_id": "...",
"client_secret": "..."
}
Output:
{
"access_token": "...",
"expires_in": 27972,
"refresh_token": "..."
}
2. Get Profile
Doc: 02-GET-PROFILE.md
Endpoint: GET /api/v1/credentials/me
Purpose: Lấy thông tin user đã login
Input: Bearer token in header
Output:
{
"data": {
"attributes": {
"email": "user@example.com",
"first_name": "John",
"last_name": "Doe",
"agency": {
"code": "ST2010",
"name": "My Agency"
}
}
}
}
🎯 Complete Example
// Step 1: Login
async function login(email, password) {
const response = await fetch("{{base_url}}/oauth/token", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
grant_type: "password",
email: email,
password: password,
client_id: "gSwj9376QaRBMFOgcV8mcPUDitZ_X_DsE1EqAlun7iQ",
client_secret: "your-secret",
}),
});
const data = await response.json();
if (data.access_token) {
return data.access_token;
}
throw new Error("Login failed");
}
// Step 2: Get Profile
async function getProfile(accessToken) {
const response = await fetch("{{base_url}}/api/v1/credentials/me", {
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
});
const data = await response.json();
return data.data.attributes;
}
// Step 3: Use
const token = await login("user@example.com", "password");
const profile = await getProfile(token);
console.log("Logged in as:", profile.email);
console.log("Agency:", profile.agency.name);
console.log("Agency Code:", profile.agency.code);
// Store for later use
localStorage.setItem("access_token", token);
localStorage.setItem("agency_code", profile.agency.code);
⚠️ Important Rules
1. Token Lifetime
- Access token valid: ~7-8 hours (27,000-28,000 seconds)
- Store
expires_into track expiration - Re-authenticate when expired
2. Secure Storage
// ✅ Good - Store securely
sessionStorage.setItem("access_token", token); // Clears on close
// ⚠️ Caution - Persistent storage
localStorage.setItem("access_token", token); // Persists
// ❌ Bad - Never log in production
console.log("Token:", token); // Security risk!
3. Token Usage
All booking APIs require token in header:
headers: {
'Authorization': `Bearer ${access_token}`
}
4. Agency Code
Save agency.code from profile - used throughout system:
- Booking metadata
- Commission tracking
- Reports
- Invoices
🔒 Security Best Practices
1. Never Hardcode Credentials
// ❌ Bad
const email = "user@example.com";
const password = "hardcoded-password";
// ✅ Good
const email = process.env.EMAIL;
const password = process.env.PASSWORD;
2. Handle Token Expiration
const tokenExpiry = Date.now() + response.expires_in * 1000;
// Before each API call
if (Date.now() >= tokenExpiry) {
accessToken = await login(email, password);
}
3. Validate Account Status
const profile = await getProfile(token);
if (!profile.active || profile.locked) {
throw new Error("Account inactive or locked");
}
4. Clear on Logout
function logout() {
localStorage.removeItem("access_token");
localStorage.removeItem("agency_code");
sessionStorage.clear();
}
🐛 Common Issues
Invalid Credentials (401)
Error: "error": "invalid_grant"
Solution: Check email/password are correct
Token Expired (401)
Error: "error": "Unauthorized"
Solution: Re-authenticate to get new token
Account Locked
Profile: "locked": true, "active": false
Action: Contact admin to unlock
📊 Token Lifecycle
🔗 Next Steps
After authentication:
-
Book Flights →
../booking-flows/README.md- Search flights
- Add services/seats
- Hold or Issue ticket
-
Manage Bookings →
../manage-booking/- List bookings
- Get details
- Add services
- Payment
📝 Summary
Required Steps:
- POST
/oauth/token→ Get access_token - GET
/credentials/me→ Get user profile & agency info - Store token & agency_code
- Use token in all subsequent API calls
Token Info:
- Lifetime: 7-8 hours
- Type: Bearer
- Scope: public
Key Data to Store:
access_token- For API callsagency.code- For bookingsexpires_in- To track expiration