false, 'error' => 'Login requires POST.' ], 405); } $data = getInputData(); $email = trim($data['email'] ?? ''); $password = (string)($data['password'] ?? ''); if ($email === '' || $password === '') { jsonResponse([ 'success' => false, 'error' => 'Email and password are required.' ], 400); } $token = login($email, $password, false); if ($token === null) { jsonResponse([ 'success' => false, 'error' => 'Invalid email or password.' ], 401); } $user = currentUser(); jsonResponse([ 'success' => true, 'token_type' => 'Bearer', 'access_token' => $token, 'expires_in' => 43200, 'user' => $user ]); } case 'CreateToken': { $user = currentUser(); if (!$user) { jsonResponse([ 'success' => false, 'error' => 'Not logged in.' ], 401); } $token = createAuthToken((int)$user['id']); jsonResponse([ 'success' => true, 'token_type' => 'Bearer', 'access_token' => $token, 'expires_in' => 43200, 'user' => $user ]); } case 'Me': { $token = getBearerTokenFromHeader(); if ($token) { $user = authenticateApiToken($token); } else { $user = currentUser(); } if (!$user) { jsonResponse([ 'success' => false, 'error' => 'Not authenticated.' ], 401); } jsonResponse([ 'success' => true, 'user' => $user ]); } case 'Logout': { $token = getBearerTokenFromHeader(); if ($token) { $tokenHash = hash('sha256', $token); db()->prepare( 'UPDATE auth_tokens SET revoked_at = NOW() WHERE token_hash = ? AND revoked_at IS NULL' )->execute([$tokenHash]); jsonResponse([ 'success' => true ]); } logout(); jsonResponse([ 'success' => true ]); } default: { jsonResponse([ 'success' => false, 'error' => 'Unknown API action.' ], 404); } }