Fix: trim CurseForge API key + add debug logging for 403 diagnosis

Key may have whitespace from dbGet. Added Log::debug with key length
and modpack ID to diagnose the 403.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude (Chronicler #83 - The Compiler)
2026-04-12 22:57:23 -05:00
parent 28f2c3d904
commit 31f245a1b9
2 changed files with 39 additions and 2 deletions

View File

@@ -0,0 +1,35 @@
# Chronicler Dispatch — CurseForge 403: API key not being sent correctly
**Date:** 2026-04-12
**From:** Chronicler #84 — The Meridian
**To:** Code
---
## Diagnosis
CurseForge API key IS valid and stored correctly. Tested via PHP tinker:
```php
$key = $bp->dbGet('modpackchecker', 'curseforge_api_key');
// Returns valid key, length 60
file_get_contents('https://api.curseforge.com/v1/mods/925200', false,
stream_context_create(['http' => ['header' => 'x-api-key: ' . $key . "\r\n"]]));
// Returns valid JSON data ✅
```
So the key works. The 403s are coming from `ModpackApiService.php` — it's not passing the key correctly to CurseForge.
## What to Check in ModpackApiService.php
1. Is it reading the key via `$bp->dbGet('modpackchecker', 'curseforge_api_key')`?
2. Is it using `x-api-key` header (NOT `Authorization: Bearer`)?
3. Is there any string processing of the key that might corrupt the `$` characters?
The CurseForge API requires `x-api-key: <key>` as the header. Laravel's Http facade should work fine:
```php
Http::withHeaders(['x-api-key' => $apiKey])->get('https://api.curseforge.com/v1/mods/' . $modpackId)
```
*— Chronicler #84, The Meridian*

View File

@@ -110,12 +110,14 @@ class ModpackApiService
*/
private function checkCurseForge(string $modpackId): array
{
$apiKey = $this->blueprint->dbGet('modpackchecker', 'curseforge_api_key');
$apiKey = trim($this->blueprint->dbGet('modpackchecker', 'curseforge_api_key') ?? '');
if (empty($apiKey)) {
throw new Exception('CurseForge API key not configured');
}
\Log::debug('[MVC] CurseForge API call — key length: ' . strlen($apiKey) . ', modpack: ' . $modpackId);
$response = Http::timeout(10)->withHeaders([
'x-api-key' => $apiKey,
'Accept' => 'application/json',