Pagpapatunay
Gumagamit ang SMSBAT ChatHub API ng two-level na JWT token-based authentication system na may mga token ng kumpanya at operator token.
Daloy ng Pagpapatotoo
graph TD
A[Login Credentials] --> B[Get Company Token]
B --> C[Use Company Token]
C --> D[Get Operator Token]
D --> E[Use Operator Token]
E --> F[Validate Token]
Token ng Kumpanya
Ang mga token ng kumpanya ay nagbibigay ng access sa antas ng organisasyon sa ChatHub API.
Kumuha ng Token ng Kumpanya
Endpoint: POST /api/company/get-token
Kahilingan:
curl -X POST https://chatapi.smsbat.com/api/company/get-token \
-H "Content-Type: application/json" \
-d '{
"login": "your-company-login",
"password": "your-company-password"
}'
Katawan ng Kahilingan:
Tugon:
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
Ang tugon ay isang JWT token string.
Gumamit ng Company Token
Isama ang token ng kumpanya sa mga kahilingan sa API gamit ang isa sa dalawang pamamaraan:
Paraan 1: Authorization Header (Inirerekomenda)
curl -X GET https://chatapi.smsbat.com/api/company/organization \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Paraan 2: X-Authorization-Key Header
curl -X GET https://chatapi.smsbat.com/api/company/organization \
-H "X-Authorization-Key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Token ng Operator
Ang mga operator token ay nagbibigay ng access na partikular sa user para sa mga indibidwal na operator sa loob ng isang organisasyon.
Kumuha ng Token ng Operator
Endpoint: POST /api/operator/get-token
Kahilingan:
curl -X POST https://chatapi.smsbat.com/api/operator/get-token \
-H "Authorization: Bearer {company-token}" \
-H "Content-Type: application/json" \
-d '{
"id": 123,
"expiresAt": "2025-12-31T23:59:59Z"
}'
Katawan ng Kahilingan:
Mga Parameter:
| Parameter | Uri | Kinakailangan | Paglalarawan |
|---|---|---|---|
id |
integer | Oo | Operator ID |
expiresSa |
string (ISO 8601) | Oo | Petsa at oras ng pag-expire ng token (max 24 na oras mula ngayon) |
Mahalaga: Ang maximum na buhay ng token ay 24 na oras. Ang parameter na expiresAt ay hindi maaaring higit sa 24 na oras sa hinaharap.
Tugon:
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcGVyYXRvcl9pZCI6MTIzLCJleHAiOjE3Mzc0MTI3OTl9.example_signature"
Gumamit ng Operator Token
Isama ang operator token sa mga kahilingan sa API:
Pagpapatunay ng Token
I-verify na valid pa rin ang isang token bago ito gamitin.
Endpoint: POST /api/operator/validate-token
Kahilingan:
curl -X POST https://chatapi.smsbat.com/api/operator/validate-token \
-H "Authorization: Bearer {company-token}" \
-H "Content-Type: application/json" \
-d '{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'
Katawan ng Kahilingan:
Tugon (Valid na Token):
{
"isValid": true,
"operatorId": 123,
"clientId": 0,
"expiresAt": "2025-12-31T23:59:59Z",
"error": null
}
Tugon (Di-wastong Token):
Pag-expire ng Token
Mga Token ng Kumpanya
- Walang tahasang expiration sa API
- Makipag-ugnayan sa iyong account manager para sa mga patakaran sa token lifecycle
- Paikutin ang mga token sa pana-panahon para sa seguridad
Mga Token ng Operator
- Itinakda ang expiration kapag humihiling ng token (parameter na
expiresAt) - I-validate ang mga token bago gamitin
- Humiling ng mga bagong token bago mag-expire
Mga Halimbawa ng Pagpapatupad
Sawa
import requests
from datetime import datetime, timedelta
class ChatHubAuth:
def __init__(self, base_url):
self.base_url = base_url
self.company_token = None
self.operator_tokens = {}
def get_company_token(self, login, password):
"""Get company authentication token"""
response = requests.post(
f"{self.base_url}/api/company/get-token",
json={"login": login, "password": password}
)
response.raise_for_status()
self.company_token = response.json()
return self.company_token
def get_operator_token(self, operator_id, expires_days=30):
"""Get operator token with expiration"""
expires_at = (
datetime.utcnow() + timedelta(days=expires_days)
).isoformat() + "Z"
response = requests.post(
f"{self.base_url}/api/operator/get-token",
headers={"Authorization": f"Bearer {self.company_token}"},
json={"id": operator_id, "expiresAt": expires_at}
)
response.raise_for_status()
token = response.json()
self.operator_tokens[operator_id] = token
return token
def validate_token(self, token):
"""Validate if token is still valid"""
response = requests.post(
f"{self.base_url}/api/operator/validate-token",
headers={"Authorization": f"Bearer {self.company_token}"},
json={"token": token}
)
response.raise_for_status()
return response.json()
# Usage
auth = ChatHubAuth("https://chatapi.smsbat.com")
# Get company token
company_token = auth.get_company_token("login", "password")
# Get operator token
operator_token = auth.get_operator_token(operator_id=123, expires_days=30)
# Validate token
is_valid = auth.validate_token(operator_token)
print(f"Token valid: {is_valid['valid']}")
JavaScript (Node.js)
const axios = require('axios');
class ChatHubAuth {
constructor(baseUrl) {
this.baseUrl = baseUrl;
this.companyToken = null;
this.operatorTokens = {};
}
async getCompanyToken(login, password) {
const response = await axios.post(
`${this.baseUrl}/api/company/get-token`,
{ login, password }
);
this.companyToken = response.data;
return this.companyToken;
}
async getOperatorToken(operatorId, expiresDays = 30) {
const expiresAt = new Date(
Date.now() + expiresDays * 24 * 60 * 60 * 1000
).toISOString();
const response = await axios.post(
`${this.baseUrl}/api/operator/get-token`,
{ id: operatorId, expiresAt },
{
headers: {
Authorization: `Bearer ${this.companyToken}`
}
}
);
const token = response.data;
this.operatorTokens[operatorId] = token;
return token;
}
async validateToken(token) {
const response = await axios.post(
`${this.baseUrl}/api/operator/validate-token`,
{ token },
{
headers: {
Authorization: `Bearer ${this.companyToken}`
}
}
);
return response.data;
}
}
// Usage
const auth = new ChatHubAuth('https://chatapi.smsbat.com');
async function authenticate() {
// Get company token
const companyToken = await auth.getCompanyToken('login', 'password');
// Get operator token
const operatorToken = await auth.getOperatorToken(123, 30);
// Validate token
const validation = await auth.validateToken(operatorToken);
console.log('Token valid:', validation.isValid);
}
authenticate();
PHP
<?php
class ChatHubAuth {
private $baseUrl;
private $companyToken;
private $operatorTokens = [];
public function __construct($baseUrl) {
$this->baseUrl = $baseUrl;
}
public function getCompanyToken($login, $password) {
$ch = curl_init($this->baseUrl . '/api/company/get-token');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'login' => $login,
'password' => $password
]));
$response = curl_exec($ch);
curl_close($ch);
$this->companyToken = json_decode($response);
return $this->companyToken;
}
public function getOperatorToken($operatorId, $expiresDays = 30) {
$expiresAt = date(
'Y-m-d\TH:i:s\Z',
time() + ($expiresDays * 24 * 60 * 60)
);
$ch = curl_init($this->baseUrl . '/api/operator/get-token');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->companyToken
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'id' => $operatorId,
'expiresAt' => $expiresAt
]));
$response = curl_exec($ch);
curl_close($ch);
$token = json_decode($response);
$this->operatorTokens[$operatorId] = $token;
return $token;
}
public function validateToken($token) {
$ch = curl_init($this->baseUrl . '/api/operator/validate-token');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->companyToken
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'token' => $token
]));
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
}
// Usage
$auth = new ChatHubAuth('https://chatapi.smsbat.com');
// Get company token
$companyToken = $auth->getCompanyToken('login', 'password');
// Get operator token
$operatorToken = $auth->getOperatorToken(123, 30);
// Validate token
$validation = $auth->validateToken($operatorToken);
echo "Token valid: " . ($validation['isValid'] ? 'Yes' : 'No');
Pinakamahuhusay na Kasanayan
Imbakan ng Token
- ✅ Ligtas na mag-imbak ng mga token (naka-encrypt na database, secrets manager)
- ✅ Huwag kailanman mag-commit ng mga token sa version control
- ✅ Gumamit ng mga variable ng kapaligiran para sa mga kredensyal
- ❌ Huwag mag-imbak ng mga token sa plain text
- ❌ Huwag ilantad ang mga token sa client-side code
Pag-ikot ng Token
- Paikutin ang mga token ng kumpanya sa pana-panahon (bawat 3-6 na buwan)
- Magtakda ng makatwirang expiration para sa mga token ng operator (7-30 araw)
- Ipatupad ang awtomatikong pag-refresh ng token bago mag-expire
- Bawiin ang mga token kapag umalis ang mga operator
Error sa Paghawak
async function authenticateWithRetry(login, password, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await getCompanyToken(login, password);
} catch (error) {
if (error.response?.status === 401) {
throw new Error('Invalid credentials');
}
if (i === retries - 1) throw error;
// Wait before retry
await new Promise(resolve =>
setTimeout(resolve, Math.pow(2, i) * 1000)
);
}
}
}
Pagpapatunay ng Token
Palaging i-validate ang mga token bago ang mga kritikal na operasyon:
async function performSecureOperation(token, operation) {
// Validate token first
const validation = await validateToken(token);
if (!validation.isValid) {
throw new Error('Token expired or invalid');
}
// Proceed with operation
return await operation();
}
Mga Pagsasaalang-alang sa Seguridad
HTTPS Lang
Palaging gumamit ng HTTPS kapag nagpapadala ng mga kahilingan sa pagpapatunay:
// ✅ Correct
const baseUrl = 'https://chatapi.smsbat.com';
// ❌ Wrong - never use HTTP for authentication
const baseUrl = 'http://api.chathub.smsbat.com';
Saklaw ng Token
Gamitin ang naaangkop na token para sa bawat operasyon:
- Token ng Kumpanya: Pamamahala ng organisasyon, paggawa ng operator
- Token ng Operator: Mga pagpapatakbo ng chat, paghawak ng mensahe
Paglilimita sa Rate
Ipatupad ang paglilimita sa rate para sa mga kahilingan sa pagpapatunay:
class RateLimitedAuth {
constructor() {
this.lastRequest = 0;
this.minInterval = 1000; // 1 second between requests
}
async getToken(login, password) {
const now = Date.now();
const timeSinceLastRequest = now - this.lastRequest;
if (timeSinceLastRequest < this.minInterval) {
await new Promise(resolve =>
setTimeout(resolve, this.minInterval - timeSinceLastRequest)
);
}
this.lastRequest = Date.now();
return await makeAuthRequest(login, password);
}
}
Pag-troubleshoot
401 Hindi awtorisado
- I-verify na tama ang mga kredensyal
- Hindi pa nag-expire ang check token
- Tiyaking kasama ang token sa mga header ng kahilingan
- Patunayan ang format ng token
403 Bawal
- I-verify na ang token ay may mga kinakailangang pahintulot
- Suriin kung gumagamit ng tamang uri ng token (kumpanya vs operator)
- Tiyaking hindi binawi ang token
Nag-expire na ang Token
- Humiling ng bagong token
- Ipatupad ang awtomatikong pag-refresh ng token
- Itakda ang naaangkop na mga oras ng pag-expire
Mga Susunod na Hakbang
- Mga Organisasyon - Pamahalaan ang mga organisasyon
- Operator - Makipagtulungan sa mga operator
- Pagsasama ng Widget - Pagsamahin ang widget ng chat