Skip to main content

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:

  1. OAuth Token - Đăng nhập và lấy access token
  2. 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_in to 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:

  1. Book Flights../booking-flows/README.md

    • Search flights
    • Add services/seats
    • Hold or Issue ticket
  2. Manage Bookings../manage-booking/

    • List bookings
    • Get details
    • Add services
    • Payment

📝 Summary

Required Steps:

  1. POST /oauth/token → Get access_token
  2. GET /credentials/me → Get user profile & agency info
  3. Store token & agency_code
  4. 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 calls
  • agency.code - For bookings
  • expires_in - To track expiration