529 lines
11 KiB
Markdown
529 lines
11 KiB
Markdown
|
|
# Backend API Documentation - Auth Service
|
||
|
|
|
||
|
|
Complete API documentation for implementing the backend for the DX Authentication Service.
|
||
|
|
|
||
|
|
## 📋 Overview
|
||
|
|
|
||
|
|
This authentication service provides QR code-based authentication with comprehensive device tracking for all DX projects (Dexar, Novo Markets, FastCheck, BackOffice).
|
||
|
|
|
||
|
|
**Base URL:**
|
||
|
|
- Development: `http://localhost:3000/api`
|
||
|
|
- Production: `https://api.dx-projects.com/api`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔐 Endpoints
|
||
|
|
|
||
|
|
### 1. Generate QR Code
|
||
|
|
|
||
|
|
Generate a new QR code session for authentication.
|
||
|
|
|
||
|
|
**Endpoint:** `POST /auth/qr/generate`
|
||
|
|
|
||
|
|
**Request Body:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"project": "dexar",
|
||
|
|
"deviceInfo": {
|
||
|
|
"deviceType": "desktop",
|
||
|
|
"deviceOS": "windows",
|
||
|
|
"context": "browser",
|
||
|
|
"project": "dexar",
|
||
|
|
"userAgent": "Mozilla/5.0...",
|
||
|
|
"screenResolution": "1920x1080",
|
||
|
|
"browserName": "Chrome",
|
||
|
|
"browserVersion": "120.0.0"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Request Schema:**
|
||
|
|
| Field | Type | Required | Description |
|
||
|
|
|-------|------|----------|-------------|
|
||
|
|
| `project` | string | Yes | Project ID: dexar, novo, fastcheck, backoffice |
|
||
|
|
| `deviceInfo.deviceType` | string\|null | No | mobile, desktop, tablet |
|
||
|
|
| `deviceInfo.deviceOS` | string\|null | No | android, ios, windows, macos, linux |
|
||
|
|
| `deviceInfo.context` | string\|null | No | browser, application, telegram |
|
||
|
|
| `deviceInfo.project` | string | Yes | Same as root project |
|
||
|
|
| `deviceInfo.userAgent` | string | No | Browser user agent |
|
||
|
|
| `deviceInfo.screenResolution` | string | No | e.g. "1920x1080" |
|
||
|
|
| `deviceInfo.browserName` | string | No | Browser name |
|
||
|
|
| `deviceInfo.browserVersion` | string | No | Browser version |
|
||
|
|
|
||
|
|
**Response:** `200 OK`
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
|
||
|
|
"qrCode": "data:image/png;base64,iVBORw0KGgo...",
|
||
|
|
"expiresAt": "2026-01-26T15:30:00.000Z",
|
||
|
|
"expiresIn": 60
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**QR Code Content Should Be:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
|
||
|
|
"apiUrl": "https://api.dx-projects.com/api"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 2. Scan QR Code (Mobile Auth)
|
||
|
|
|
||
|
|
Scan and authenticate using a QR code session.
|
||
|
|
|
||
|
|
**Endpoint:** `POST /auth/qr/scan`
|
||
|
|
|
||
|
|
**Request Body:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
|
||
|
|
"deviceInfo": {
|
||
|
|
"deviceType": "mobile",
|
||
|
|
"deviceOS": "android",
|
||
|
|
"context": "application",
|
||
|
|
"project": "dexar",
|
||
|
|
"userAgent": "Mozilla/5.0...",
|
||
|
|
"screenResolution": "1080x2400",
|
||
|
|
"browserName": "Chrome Mobile",
|
||
|
|
"browserVersion": "120.0.0"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response:** `200 OK`
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"success": true,
|
||
|
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
|
|
"userId": "user-123",
|
||
|
|
"expiresAt": "2026-01-27T14:30:00.000Z",
|
||
|
|
"message": "Authentication successful",
|
||
|
|
"userInfo": {
|
||
|
|
"username": "john_doe",
|
||
|
|
"email": "john@example.com",
|
||
|
|
"role": "admin"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 3. Check Auth Status (Polling)
|
||
|
|
|
||
|
|
Check if a QR session has been authenticated. Used for polling every 2 seconds.
|
||
|
|
|
||
|
|
**Endpoint:** `GET /auth/qr/status/:sessionId`
|
||
|
|
|
||
|
|
**Response (Not Authenticated):** `200 OK`
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"authenticated": false
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response (Authenticated):** `200 OK`
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"authenticated": true,
|
||
|
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
|
|
"userId": "user-123",
|
||
|
|
"expiresAt": "2026-01-27T14:30:00.000Z",
|
||
|
|
"userInfo": {
|
||
|
|
"username": "john_doe",
|
||
|
|
"email": "john@example.com",
|
||
|
|
"role": "admin"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 4. Traditional Login
|
||
|
|
|
||
|
|
Username/password authentication (alternative to QR).
|
||
|
|
|
||
|
|
**Endpoint:** `POST /auth/login`
|
||
|
|
|
||
|
|
**Request Body:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"username": "john_doe",
|
||
|
|
"password": "secure_password_123",
|
||
|
|
"deviceInfo": {
|
||
|
|
"deviceType": "desktop",
|
||
|
|
"deviceOS": "windows",
|
||
|
|
"context": "browser",
|
||
|
|
"project": "backoffice"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response:** `200 OK`
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"success": true,
|
||
|
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
|
|
"userId": "user-123",
|
||
|
|
"expiresAt": "2026-01-27T14:30:00.000Z",
|
||
|
|
"message": "Login successful",
|
||
|
|
"userInfo": {
|
||
|
|
"username": "john_doe",
|
||
|
|
"email": "john@example.com",
|
||
|
|
"role": "admin"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 5. Validate Session
|
||
|
|
|
||
|
|
Validate an existing JWT token.
|
||
|
|
|
||
|
|
**Endpoint:** `POST /auth/validate`
|
||
|
|
|
||
|
|
**Headers:**
|
||
|
|
```
|
||
|
|
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
|
|
```
|
||
|
|
|
||
|
|
**Request Body:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"deviceInfo": {
|
||
|
|
"deviceType": "desktop",
|
||
|
|
"deviceOS": "windows",
|
||
|
|
"context": "browser",
|
||
|
|
"project": "dexar"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response:** `200 OK`
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"valid": true,
|
||
|
|
"userId": "user-123",
|
||
|
|
"expiresAt": "2026-01-27T14:30:00.000Z",
|
||
|
|
"userInfo": {
|
||
|
|
"username": "john_doe",
|
||
|
|
"email": "john@example.com",
|
||
|
|
"role": "admin"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 6. Logout
|
||
|
|
|
||
|
|
Invalidate current session.
|
||
|
|
|
||
|
|
**Endpoint:** `POST /auth/logout`
|
||
|
|
|
||
|
|
**Headers:**
|
||
|
|
```
|
||
|
|
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
|
|
```
|
||
|
|
|
||
|
|
**Request Body:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"deviceInfo": {
|
||
|
|
"deviceType": "desktop",
|
||
|
|
"deviceOS": "windows",
|
||
|
|
"context": "browser",
|
||
|
|
"project": "dexar"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response:** `200 OK`
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"success": true,
|
||
|
|
"message": "Logged out successfully"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 💾 Database Schema
|
||
|
|
|
||
|
|
### Sessions Table
|
||
|
|
```sql
|
||
|
|
CREATE TABLE auth_sessions (
|
||
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
|
|
session_id VARCHAR(255) UNIQUE NOT NULL,
|
||
|
|
project VARCHAR(50) NOT NULL,
|
||
|
|
device_type VARCHAR(20),
|
||
|
|
device_os VARCHAR(20),
|
||
|
|
context VARCHAR(20),
|
||
|
|
user_agent TEXT,
|
||
|
|
screen_resolution VARCHAR(20),
|
||
|
|
browser_name VARCHAR(50),
|
||
|
|
browser_version VARCHAR(20),
|
||
|
|
authenticated BOOLEAN DEFAULT FALSE,
|
||
|
|
user_id UUID,
|
||
|
|
ip_address VARCHAR(45),
|
||
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
||
|
|
expires_at TIMESTAMP NOT NULL,
|
||
|
|
authenticated_at TIMESTAMP,
|
||
|
|
INDEX idx_session_id (session_id),
|
||
|
|
INDEX idx_expires_at (expires_at),
|
||
|
|
INDEX idx_user_id (user_id)
|
||
|
|
);
|
||
|
|
```
|
||
|
|
|
||
|
|
### Auth Logs Table
|
||
|
|
```sql
|
||
|
|
CREATE TABLE auth_logs (
|
||
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
|
|
user_id UUID,
|
||
|
|
project VARCHAR(50) NOT NULL,
|
||
|
|
action VARCHAR(50) NOT NULL, -- login, logout, qr_scan, validate, qr_generate
|
||
|
|
device_type VARCHAR(20),
|
||
|
|
device_os VARCHAR(20),
|
||
|
|
context VARCHAR(20),
|
||
|
|
user_agent TEXT,
|
||
|
|
ip_address VARCHAR(45),
|
||
|
|
success BOOLEAN,
|
||
|
|
error_message TEXT,
|
||
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
||
|
|
INDEX idx_user_id (user_id),
|
||
|
|
INDEX idx_created_at (created_at),
|
||
|
|
INDEX idx_project (project)
|
||
|
|
);
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔒 Security Implementation
|
||
|
|
|
||
|
|
### Password Hashing
|
||
|
|
```javascript
|
||
|
|
const bcrypt = require('bcrypt');
|
||
|
|
const saltRounds = 12;
|
||
|
|
|
||
|
|
// Hash password
|
||
|
|
const hashedPassword = await bcrypt.hash(password, saltRounds);
|
||
|
|
|
||
|
|
// Verify password
|
||
|
|
const isValid = await bcrypt.compare(password, hashedPassword);
|
||
|
|
```
|
||
|
|
|
||
|
|
### JWT Token Generation
|
||
|
|
```javascript
|
||
|
|
const jwt = require('jsonwebtoken');
|
||
|
|
|
||
|
|
const token = jwt.sign(
|
||
|
|
{
|
||
|
|
userId: user.id,
|
||
|
|
project: deviceInfo.project,
|
||
|
|
deviceType: deviceInfo.deviceType
|
||
|
|
},
|
||
|
|
process.env.JWT_SECRET,
|
||
|
|
{ expiresIn: '24h' }
|
||
|
|
);
|
||
|
|
```
|
||
|
|
|
||
|
|
### QR Code Generation
|
||
|
|
```javascript
|
||
|
|
const QRCode = require('qrcode');
|
||
|
|
|
||
|
|
const qrData = {
|
||
|
|
sessionId: sessionId,
|
||
|
|
apiUrl: process.env.API_URL
|
||
|
|
};
|
||
|
|
|
||
|
|
const qrCodeImage = await QRCode.toDataURL(JSON.stringify(qrData));
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🚀 Implementation Flow
|
||
|
|
|
||
|
|
### QR Authentication Flow
|
||
|
|
|
||
|
|
1. **Desktop Browser Requests QR Code**
|
||
|
|
- POST `/auth/qr/generate` with desktop device info
|
||
|
|
- Backend creates session in database
|
||
|
|
- Returns QR code image
|
||
|
|
|
||
|
|
2. **Frontend Starts Polling**
|
||
|
|
- Every 2 seconds: GET `/auth/qr/status/:sessionId`
|
||
|
|
- Backend returns `{ authenticated: false }`
|
||
|
|
|
||
|
|
3. **Mobile App Scans QR**
|
||
|
|
- Parse QR code to get sessionId
|
||
|
|
- POST `/auth/qr/scan` with mobile device info
|
||
|
|
- Backend authenticates user
|
||
|
|
- Backend updates session as authenticated
|
||
|
|
- Returns JWT token
|
||
|
|
|
||
|
|
4. **Desktop Polling Detects Auth**
|
||
|
|
- Next poll returns `{ authenticated: true, token: "..." }`
|
||
|
|
- Frontend stores token
|
||
|
|
- Redirects to application
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📊 Device Info Tracking
|
||
|
|
|
||
|
|
### When to Send Device Info
|
||
|
|
|
||
|
|
**Send device info on:**
|
||
|
|
- ✅ QR code generation (desktop)
|
||
|
|
- ✅ QR code scanning (mobile)
|
||
|
|
- ✅ Traditional login
|
||
|
|
- ✅ Session validation
|
||
|
|
- ✅ Logout
|
||
|
|
|
||
|
|
**Device Info Rules:**
|
||
|
|
- All fields except `project` are optional
|
||
|
|
- Send `null` for unknown values
|
||
|
|
- Never fail request if device info is incomplete
|
||
|
|
- Log all device info for analytics
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## ⚠️ Error Handling
|
||
|
|
|
||
|
|
### Error Response Format
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"error": true,
|
||
|
|
"message": "Invalid credentials",
|
||
|
|
"code": "INVALID_CREDENTIALS"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Error Codes
|
||
|
|
| Code | HTTP Status | Description |
|
||
|
|
|------|-------------|-------------|
|
||
|
|
| `INVALID_PROJECT` | 400 | Unknown project identifier |
|
||
|
|
| `INVALID_SESSION` | 401 | Session not found or expired |
|
||
|
|
| `INVALID_CREDENTIALS` | 401 | Wrong username/password |
|
||
|
|
| `INVALID_TOKEN` | 401 | JWT token invalid or expired |
|
||
|
|
| `SESSION_EXPIRED` | 401 | QR code session expired |
|
||
|
|
| `RATE_LIMIT_EXCEEDED` | 429 | Too many requests |
|
||
|
|
| `SERVER_ERROR` | 500 | Internal server error |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🧪 Testing
|
||
|
|
|
||
|
|
### Test Data
|
||
|
|
|
||
|
|
**Test User:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"username": "test_user",
|
||
|
|
"password": "Test123!",
|
||
|
|
"email": "test@dx-projects.com",
|
||
|
|
"role": "user"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Example cURL Commands
|
||
|
|
|
||
|
|
**Generate QR Code:**
|
||
|
|
```bash
|
||
|
|
curl -X POST http://localhost:3000/api/auth/qr/generate \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d '{
|
||
|
|
"project": "dexar",
|
||
|
|
"deviceInfo": {
|
||
|
|
"deviceType": "desktop",
|
||
|
|
"deviceOS": "windows",
|
||
|
|
"context": "browser",
|
||
|
|
"project": "dexar"
|
||
|
|
}
|
||
|
|
}'
|
||
|
|
```
|
||
|
|
|
||
|
|
**Check Status:**
|
||
|
|
```bash
|
||
|
|
curl http://localhost:3000/api/auth/qr/status/{sessionId}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Login:**
|
||
|
|
```bash
|
||
|
|
curl -X POST http://localhost:3000/api/auth/login \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d '{
|
||
|
|
"username": "test_user",
|
||
|
|
"password": "Test123!",
|
||
|
|
"deviceInfo": {
|
||
|
|
"deviceType": "desktop",
|
||
|
|
"deviceOS": "windows",
|
||
|
|
"context": "browser",
|
||
|
|
"project": "dexar"
|
||
|
|
}
|
||
|
|
}'
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📌 Important Notes
|
||
|
|
|
||
|
|
1. **QR Code Expiration:** 60 seconds (configurable)
|
||
|
|
2. **JWT Token Expiration:** 24 hours (configurable)
|
||
|
|
3. **Polling Interval:** 2 seconds
|
||
|
|
4. **Rate Limiting:** 60 requests/minute per IP
|
||
|
|
5. **CORS:** Allow all project domains
|
||
|
|
6. **Session Cleanup:** Delete expired sessions every hour
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔧 Environment Variables
|
||
|
|
|
||
|
|
```env
|
||
|
|
# API Configuration
|
||
|
|
PORT=3000
|
||
|
|
API_URL=http://localhost:3000/api
|
||
|
|
NODE_ENV=development
|
||
|
|
|
||
|
|
# JWT
|
||
|
|
JWT_SECRET=your-super-secret-jwt-key-change-this
|
||
|
|
JWT_EXPIRATION=24h
|
||
|
|
|
||
|
|
# Database
|
||
|
|
DB_HOST=localhost
|
||
|
|
DB_PORT=5432
|
||
|
|
DB_NAME=dx_auth
|
||
|
|
DB_USER=postgres
|
||
|
|
DB_PASSWORD=your-password
|
||
|
|
|
||
|
|
# QR Code
|
||
|
|
QR_EXPIRATION=60
|
||
|
|
QR_SIZE=240
|
||
|
|
|
||
|
|
# CORS
|
||
|
|
CORS_ORIGINS=http://localhost:4200,http://localhost:4300,http://localhost:4400
|
||
|
|
|
||
|
|
# Rate Limiting
|
||
|
|
RATE_LIMIT_WINDOW=60000
|
||
|
|
RATE_LIMIT_MAX_REQUESTS=60
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📚 Additional Resources
|
||
|
|
|
||
|
|
- **Frontend Integration:** See `HOW_TO_USE.md`
|
||
|
|
- **Project Setup:** See `README.md`
|
||
|
|
- **FastCheck APIs:** Reference similar implementation in FastCheck project
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🆘 Support
|
||
|
|
|
||
|
|
For backend implementation questions:
|
||
|
|
- Email: backend@dx-projects.com
|
||
|
|
- Slack: #backend-auth
|
||
|
|
- Documentation: https://docs.dx-projects.com/auth
|