createToken(TokenKind::Admin, role: Role::Admin); $reporterId = $this->createReporter('web-tokens'); $resp = $this->request( 'POST', '/api/v1/admin/tokens', ['Authorization' => 'Bearer ' . $admin, 'Content-Type' => 'application/json'], json_encode(['kind' => 'reporter', 'reporter_id' => $reporterId]) ?: null, ); self::assertSame(201, $resp->getStatusCode()); $body = $this->decode($resp); self::assertSame('reporter', $body['kind']); self::assertSame($reporterId, $body['reporter_id']); self::assertArrayHasKey('raw_token', $body); self::assertStringStartsWith('irdb_rep_', (string) $body['raw_token']); // Second fetch via list must not include raw_token. $list = $this->request('GET', '/api/v1/admin/tokens', [ 'Authorization' => 'Bearer ' . $admin, ]); $listBody = $this->decode($list); foreach ($listBody['data'] as $row) { self::assertArrayNotHasKey('raw_token', $row); } } public function testCreateAdminTokenRequiresRole(): void { $admin = $this->createToken(TokenKind::Admin, role: Role::Admin); $resp = $this->request( 'POST', '/api/v1/admin/tokens', ['Authorization' => 'Bearer ' . $admin, 'Content-Type' => 'application/json'], json_encode(['kind' => 'admin']) ?: null, ); self::assertSame(400, $resp->getStatusCode()); self::assertArrayHasKey('role', $this->decode($resp)['details']); } public function testServiceKindRefused(): void { $admin = $this->createToken(TokenKind::Admin, role: Role::Admin); $resp = $this->request( 'POST', '/api/v1/admin/tokens', ['Authorization' => 'Bearer ' . $admin, 'Content-Type' => 'application/json'], json_encode(['kind' => 'service']) ?: null, ); self::assertSame(400, $resp->getStatusCode()); } public function testListExcludesServiceTokens(): void { $admin = $this->createToken(TokenKind::Admin, role: Role::Admin); $this->createToken(TokenKind::Service); $resp = $this->request('GET', '/api/v1/admin/tokens', [ 'Authorization' => 'Bearer ' . $admin, ]); $body = $this->decode($resp); foreach ($body['data'] as $row) { self::assertNotSame('service', $row['kind']); } } public function testRevokeMarksRevokedAt(): void { $admin = $this->createToken(TokenKind::Admin, role: Role::Admin); $reporterId = $this->createReporter('web-revoke'); $created = $this->request( 'POST', '/api/v1/admin/tokens', ['Authorization' => 'Bearer ' . $admin, 'Content-Type' => 'application/json'], json_encode(['kind' => 'reporter', 'reporter_id' => $reporterId]) ?: null, ); $tokenId = (int) $this->decode($created)['id']; $delete = $this->request('DELETE', "/api/v1/admin/tokens/{$tokenId}", [ 'Authorization' => 'Bearer ' . $admin, ]); self::assertSame(204, $delete->getStatusCode()); $row = $this->db->fetchAssociative('SELECT revoked_at FROM api_tokens WHERE id = :id', ['id' => $tokenId]); self::assertIsArray($row); self::assertNotNull($row['revoked_at']); } }