- C1: Hash refresh tokens before DB storage (sha256) - C2: Remove JWT_SECRET fallback, fail hard if missing - H1: Enforce HTTP methods per route (405 on mismatch) - H2: CORS with origin whitelist from CORS_ORIGIN env var - H3: Redact sensitive fields (tokens, passwords) from logs - M1: Build HmacMiddleware with replay attack prevention - M2: Fix rate limiter race condition with flock LOCK_EX - M3: Guard dd() — suppressed in production - M4: Remove .env from git tracking, strengthen .gitignore - I1: Add HSTS header (max-age=31536000)
48 lines
1.2 KiB
PHP
48 lines
1.2 KiB
PHP
<?php
|
|
/**
|
|
* Auth Refresh Endpoint
|
|
*/
|
|
|
|
use App\Core\Database;
|
|
use App\Core\JWT;
|
|
|
|
$data = input();
|
|
$refreshToken = $data['refresh_token'] ?? null;
|
|
|
|
if (!$refreshToken) {
|
|
json_error('Refresh token is required', 400);
|
|
}
|
|
|
|
$db = Database::getInstance();
|
|
$refreshTokenHash = hash('sha256', $refreshToken);
|
|
$stmt = $db->prepare("SELECT * FROM users WHERE refresh_token_hash = ? LIMIT 1");
|
|
$stmt->execute([$refreshTokenHash]);
|
|
$user = $stmt->fetch();
|
|
|
|
if (!$user) {
|
|
json_error('Invalid refresh token', 401);
|
|
}
|
|
|
|
$secret = env('JWT_SECRET');
|
|
if (!$secret || strlen($secret) < 32) {
|
|
error_log('FATAL: JWT_SECRET is missing or too short in .env');
|
|
json_error('Server configuration error', 500);
|
|
}
|
|
$payload = [
|
|
'user_id' => $user['id'],
|
|
'role' => $user['role'],
|
|
'exp' => time() + (15 * 60)
|
|
];
|
|
|
|
$newToken = JWT::encode($payload, $secret);
|
|
$newRefreshToken = bin2hex(random_bytes(32));
|
|
$newRefreshTokenHash = hash('sha256', $newRefreshToken);
|
|
|
|
$stmt = $db->prepare("UPDATE users SET refresh_token_hash = ? WHERE id = ?");
|
|
$stmt->execute([$newRefreshTokenHash, $user['id']]);
|
|
|
|
json_success([
|
|
'access_token' => $newToken,
|
|
'refresh_token' => $newRefreshToken
|
|
], 'تم تجديد الجلسة بنجاح');
|