enhanced token management by adding optional expiry refresh in token_get_record and updated session API documentation
Some checks failed
PHPUnit / test (push) Has been cancelled

This commit is contained in:
2026-06-24 10:23:19 +02:00
parent b02f264b23
commit 67858d34d9
4 changed files with 43 additions and 10 deletions

View File

@ -178,14 +178,29 @@ function token_add(string $token, int $ttlSeconds = 86400, array $extra = []): v
qdb_save($tmpDb, $lockFp); qdb_save($tmpDb, $lockFp);
} }
function token_get_record(string $token): ?array { function token_get_record(string $token, bool $refreshExpiry = true): ?array {
require_once __DIR__ . '/db_init.php'; require_once __DIR__ . '/db_init.php';
[$pdo, $tmpDb, $lockFp] = qdb_open(false); require_once __DIR__ . '/lib/settings.php';
[$pdo, $tmpDb, $lockFp] = qdb_open($refreshExpiry);
$now = time();
$stmt = $pdo->prepare("SELECT * FROM session WHERE token = :t AND expiresAt >= :now"); $stmt = $pdo->prepare("SELECT * FROM session WHERE token = :t AND expiresAt >= :now");
$stmt->execute([':t' => token_storage_key($token), ':now' => time()]); $storedToken = token_storage_key($token);
$stmt->execute([':t' => $storedToken, ':now' => $now]);
$row = $stmt->fetch(PDO::FETCH_ASSOC); $row = $stmt->fetch(PDO::FETCH_ASSOC);
qdb_discard($tmpDb, $lockFp); if (!$row) {
if (!$row) return null; qdb_discard($tmpDb, $lockFp);
return null;
}
if ($refreshExpiry) {
$settings = qdb_settings_get_on_pdo($pdo);
$newExpiry = $now + qdb_session_ttl_seconds($settings, !empty($row['temp']));
$pdo->prepare('UPDATE session SET expiresAt = :exp WHERE token = :t')
->execute([':exp' => $newExpiry, ':t' => $storedToken]);
$row['expiresAt'] = $newExpiry;
qdb_save($tmpDb, $lockFp);
} else {
qdb_discard($tmpDb, $lockFp);
}
// Map DB columns to the keys the rest of the codebase expects // Map DB columns to the keys the rest of the codebase expects
return [ return [
'token' => $row['token'], 'token' => $row['token'],

View File

@ -1,7 +1,7 @@
<?php <?php
/** /**
* GET /api/session — verify Bearer token is still active (website session check). * GET /api/session — verify Bearer token is still active and return role metadata.
*/ */
if ($method !== 'GET') { if ($method !== 'GET') {
@ -19,9 +19,6 @@ if (!$rec) {
} }
$role = (string)($rec['role'] ?? ''); $role = (string)($rec['role'] ?? '');
if ($role === 'coach') {
json_error('FORBIDDEN', 'Counselor accounts can only sign in through the mobile app.', 403);
}
$username = ''; $username = '';
if (($rec['userID'] ?? '') !== '') { if (($rec['userID'] ?? '') !== '') {

View File

@ -255,7 +255,7 @@ function qdb_api_log_finish(): void
if ($token !== null && $token !== '') { if ($token !== null && $token !== '') {
$auth['token_hint'] = qdb_api_log_token_hint($token); $auth['token_hint'] = qdb_api_log_token_hint($token);
try { try {
$rec = token_get_record($token); $rec = token_get_record($token, false);
if (is_array($rec)) { if (is_array($rec)) {
$auth['role'] = $rec['role'] ?? null; $auth['role'] = $rec['role'] ?? null;
$auth['userID'] = $rec['userID'] ?? null; $auth['userID'] = $rec['userID'] ?? null;

View File

@ -41,4 +41,25 @@ final class TokenTest extends QdbTestCase
$this->assertGreaterThanOrEqual(2, $n); $this->assertGreaterThanOrEqual(2, $n);
$this->assertNull(token_get_record($t1)); $this->assertNull(token_get_record($t1));
} }
public function testTokenLookupRefreshesExpiry(): void
{
$token = bin2hex(random_bytes(32));
$f = $this->fixture();
token_add($token, 3600, [
'userID' => $f->adminUserId,
'role' => 'admin',
'entityID' => 'ent',
]);
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
$oldExpiry = time() + 60;
$pdo->prepare('UPDATE session SET expiresAt = :exp WHERE token = :t')
->execute([':exp' => $oldExpiry, ':t' => token_storage_key($token)]);
qdb_save($tmpDb, $lockFp);
$rec = token_get_record($token);
$this->assertNotNull($rec);
$this->assertGreaterThan($oldExpiry + 3000, $rec['exp']);
}
} }