422 lines
8.4 KiB
Markdown
422 lines
8.4 KiB
Markdown
# EasyStream API Authentication Guide
|
|
|
|
## Overview
|
|
|
|
EasyStream now supports modern JWT token-based authentication for API clients, alongside traditional session-based authentication for web pages.
|
|
|
|
## Authentication Systems
|
|
|
|
### 1. **Session-Based Authentication** (Traditional Web Pages)
|
|
- Uses PHP sessions with cookies
|
|
- Managed by `VAuth::login()` and `VAuth::logout()`
|
|
- Stored in `db_sessions` table
|
|
- Best for: Traditional server-rendered pages
|
|
|
|
### 2. **JWT Token Authentication** (Modern APIs)
|
|
- Uses Bearer tokens in Authorization header
|
|
- Managed by `VAuth::loginWithToken()` and `VAuth::validateJWTToken()`
|
|
- Stateless (no server-side session storage)
|
|
- Best for: SPAs, mobile apps, API clients
|
|
|
|
---
|
|
|
|
## Backend API Endpoints
|
|
|
|
### Base URL
|
|
```
|
|
http://localhost:8083/api
|
|
```
|
|
|
|
### Authentication Endpoints
|
|
|
|
#### 1. **Login with Token** (New)
|
|
Get a JWT token for API authentication.
|
|
|
|
**Endpoint:** `POST /auth.php?action=login_token`
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"identifier": "username or email",
|
|
"password": "your_password",
|
|
"expires_in": 86400 // Optional: token expiry in seconds (default: 24 hours)
|
|
}
|
|
```
|
|
|
|
**Response (Success):**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Login successful",
|
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
"token_type": "Bearer",
|
|
"expires_in": 86400,
|
|
"user": {
|
|
"user_id": 1,
|
|
"username": "john_doe",
|
|
"email": "john@example.com",
|
|
"role": "member"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Response (Error):**
|
|
```json
|
|
{
|
|
"success": false,
|
|
"message": "Invalid credentials"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### 2. **Verify Token**
|
|
Validate a JWT token and get user information.
|
|
|
|
**Endpoint:** `GET /auth.php?action=verify_token` or `POST /auth.php?action=verify_token`
|
|
|
|
**Authorization Header:**
|
|
```
|
|
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
```
|
|
|
|
**Alternative (POST body):**
|
|
```json
|
|
{
|
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
}
|
|
```
|
|
|
|
**Response (Success):**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"valid": true,
|
|
"user": {
|
|
"user_id": 1,
|
|
"username": "john_doe",
|
|
"email": "john@example.com",
|
|
"role": "member"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### 3. **Traditional Login** (Session-based)
|
|
For web pages that need PHP session authentication.
|
|
|
|
**Endpoint:** `POST /auth.php?action=login`
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"identifier": "username or email",
|
|
"password": "your_password",
|
|
"remember_me": false
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Login successful",
|
|
"user": { ... }
|
|
}
|
|
```
|
|
|
|
*Note: This sets a PHP session cookie, not a JWT token.*
|
|
|
|
---
|
|
|
|
## Frontend API Helper Usage
|
|
|
|
### Include the API Helper
|
|
|
|
Add to your HTML:
|
|
```html
|
|
<script src="/f_scripts/fe/js/api-helper.js"></script>
|
|
```
|
|
|
|
### Initialize API Client
|
|
|
|
```javascript
|
|
// API client is automatically initialized as window.api
|
|
const api = window.api; // or new EasyStreamAPI()
|
|
```
|
|
|
|
### Authentication Examples
|
|
|
|
#### Login and Get Token
|
|
```javascript
|
|
try {
|
|
const result = await api.login('john_doe', 'password123');
|
|
|
|
if (result.success) {
|
|
console.log('Logged in!', result.user);
|
|
console.log('Token:', result.token);
|
|
// Token is automatically stored in localStorage
|
|
}
|
|
} catch (error) {
|
|
console.error('Login failed:', error.message);
|
|
}
|
|
```
|
|
|
|
#### Check Authentication Status
|
|
```javascript
|
|
if (api.isAuthenticated()) {
|
|
console.log('User is authenticated');
|
|
} else {
|
|
console.log('User is not authenticated');
|
|
}
|
|
```
|
|
|
|
#### Get Current User Info
|
|
```javascript
|
|
try {
|
|
const userData = await api.getCurrentUser();
|
|
console.log('Current user:', userData.user);
|
|
} catch (error) {
|
|
console.error('Not authenticated:', error);
|
|
}
|
|
```
|
|
|
|
#### Logout
|
|
```javascript
|
|
try {
|
|
await api.logout();
|
|
console.log('Logged out successfully');
|
|
} catch (error) {
|
|
console.error('Logout error:', error);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Making Authenticated API Requests
|
|
|
|
The API helper automatically includes the Bearer token in all requests.
|
|
|
|
#### GET Request
|
|
```javascript
|
|
try {
|
|
const videos = await api.get('/videos.php', {
|
|
page: 1,
|
|
limit: 20,
|
|
sort: 'newest'
|
|
});
|
|
|
|
console.log('Videos:', videos);
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
}
|
|
```
|
|
|
|
#### POST Request
|
|
```javascript
|
|
try {
|
|
const newVideo = await api.post('/videos.php', {
|
|
title: 'My Awesome Video',
|
|
description: 'Check this out!',
|
|
privacy: 'public'
|
|
});
|
|
|
|
console.log('Video created:', newVideo);
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
}
|
|
```
|
|
|
|
#### PUT Request
|
|
```javascript
|
|
try {
|
|
const updated = await api.put('/videos.php?id=123', {
|
|
title: 'Updated Title'
|
|
});
|
|
|
|
console.log('Video updated:', updated);
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
}
|
|
```
|
|
|
|
#### DELETE Request
|
|
```javascript
|
|
try {
|
|
const result = await api.delete('/videos.php?id=123');
|
|
console.log('Video deleted:', result);
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Manual Fetch Example (Without Helper)
|
|
|
|
If you prefer to use fetch() directly:
|
|
|
|
```javascript
|
|
// Login and get token
|
|
const loginResponse = await fetch('/api/auth.php?action=login_token', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
identifier: 'john_doe',
|
|
password: 'password123'
|
|
})
|
|
});
|
|
|
|
const loginData = await loginResponse.json();
|
|
const token = loginData.token;
|
|
|
|
// Store token
|
|
localStorage.setItem('jwt_token', token);
|
|
|
|
// Make authenticated request
|
|
const response = await fetch('/api/videos.php', {
|
|
method: 'GET',
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`,
|
|
'Content-Type': 'application/json'
|
|
}
|
|
});
|
|
|
|
const videos = await response.json();
|
|
```
|
|
|
|
---
|
|
|
|
## cURL Examples
|
|
|
|
### Login with Token
|
|
```bash
|
|
curl -X POST http://localhost:8083/api/auth.php?action=login_token \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"identifier": "john_doe",
|
|
"password": "password123"
|
|
}'
|
|
```
|
|
|
|
### Verify Token
|
|
```bash
|
|
curl -X GET http://localhost:8083/api/auth.php?action=verify_token \
|
|
-H "Authorization: Bearer YOUR_JWT_TOKEN_HERE"
|
|
```
|
|
|
|
### Authenticated API Request
|
|
```bash
|
|
curl -X GET http://localhost:8083/api/videos.php?page=1&limit=10 \
|
|
-H "Authorization: Bearer YOUR_JWT_TOKEN_HERE"
|
|
```
|
|
|
|
---
|
|
|
|
## Token Management
|
|
|
|
### Token Storage
|
|
- Frontend: Stored in `localStorage` with expiry time
|
|
- Backend: JWT is stateless (no server-side storage)
|
|
|
|
### Token Expiry
|
|
- Default: 24 hours (86400 seconds)
|
|
- Configurable via `JWT_EXPIRY` in `.env`
|
|
- Client automatically clears expired tokens
|
|
|
|
### Token Security
|
|
- Secret: Stored in `JWT_SECRET` environment variable
|
|
- Algorithm: HS256 (HMAC-SHA256)
|
|
- Validation: Signature verified on every request
|
|
|
|
---
|
|
|
|
## Migration Guide
|
|
|
|
### For Existing AJAX Code
|
|
|
|
**Before (jQuery with sessions):**
|
|
```javascript
|
|
$.post('/some_endpoint.php', { action: 'do_something' }, function(data) {
|
|
console.log(data);
|
|
});
|
|
```
|
|
|
|
**After (Fetch with JWT):**
|
|
```javascript
|
|
api.post('/some_endpoint.php', { action: 'do_something' })
|
|
.then(data => console.log(data))
|
|
.catch(error => console.error(error));
|
|
```
|
|
|
|
---
|
|
|
|
## Environment Configuration
|
|
|
|
Update your `.env` file:
|
|
|
|
```env
|
|
# JWT Configuration
|
|
JWT_SECRET=9a652ee880c41bafb0a81d38d54b029d63903eeaafccaa8c12880a913931f63b
|
|
JWT_EXPIRY=86400
|
|
|
|
# CORS Configuration (for separate frontends)
|
|
CORS_ORIGIN=http://localhost:3000
|
|
```
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
### Common Errors
|
|
|
|
#### 401 Unauthorized
|
|
```json
|
|
{
|
|
"success": false,
|
|
"message": "Invalid or expired token"
|
|
}
|
|
```
|
|
**Solution:** Re-login to get a new token.
|
|
|
|
#### 403 Forbidden
|
|
```json
|
|
{
|
|
"success": false,
|
|
"message": "Access denied"
|
|
}
|
|
```
|
|
**Solution:** User doesn't have permission for this resource.
|
|
|
|
#### 429 Rate Limited
|
|
```json
|
|
{
|
|
"success": false,
|
|
"message": "Too many requests"
|
|
}
|
|
```
|
|
**Solution:** Wait before retrying.
|
|
|
|
---
|
|
|
|
## Best Practices
|
|
|
|
1. **Always use HTTPS in production** - JWT tokens should be transmitted over secure connections
|
|
2. **Store tokens securely** - Use localStorage for web, secure storage for mobile
|
|
3. **Handle token expiry** - Implement token refresh or re-login flow
|
|
4. **Validate on every request** - Backend validates tokens on all protected endpoints
|
|
5. **Clear tokens on logout** - Remove tokens from storage when user logs out
|
|
6. **Use CORS properly** - Configure `Access-Control-Allow-Origin` for your frontend domain
|
|
|
|
---
|
|
|
|
## Support
|
|
|
|
For issues or questions, check:
|
|
- EasyStream documentation: `/docs/`
|
|
- API logs: `f_data/logs/`
|
|
- Error handling: `VLogger` and `VErrorHandler` classes
|