Klucze API i CORS
Uprawnienia kluczy, nagłówki uwierzytelniania, lista dozwolonych domen i limity zapytań.
Jak działa uwierzytelnianie
Gdy api.authentication.enabled: true, endpointy z danymi wymagają klucza. Klucz
podajesz w jednym z dwóch nagłówków:
X-API-Key: <klucz>Authorization: Bearer <klucz>Oba działają tak samo — wybierz ten, który wygodniej wstawić w twoim kliencie.
Endpointy bez klucza
Trzy ścieżki są zawsze publiczne:
| Ścieżka | Po co |
|---|---|
GET /api/v1/health | Sprawdzenie, czy most żyje — przydatne do monitoringu |
GET /api/docs | Dokumentacja w HTML-u |
GET /api/openapi.json | Specyfikacja OpenAPI 3 |
Uprawnienia
Każdy klucz ma własną listę uprawnień. Klucz bez danego uprawnienia dostanie 403.
Publiczne (dostępne w v1)
| Uprawnienie | Otwiera |
|---|---|
listings.read | Oferty, pojedyncza oferta, dane serwera, SSE |
categories.read | Kategorie |
stats.read | Statystyki |
history.read | Historia transakcji i wykresy cen |
players.read | Profile graczy, oferty gracza, lista sprzedawców |
Zarezerwowane (w v1 zawsze odrzucane)
| Uprawnienie | Zachowanie w v1 |
|---|---|
listings.write | 403 WRITE_NOT_ENABLED |
transactions.write | 403 WRITE_NOT_ENABLED |
admin | 403 WRITE_NOT_ENABLED |
Dlaczego most jest tylko do odczytu
Zapis przez HTTP oznaczałby, że ktoś z zewnątrz może tworzyć oferty albo ruszać ekonomię serwera. W wersji 1 celowo tego nie ma — endpointy zapisu istnieją, ale zawsze odpowiadają błędem.
Wiele kluczy
Możesz wydać osobne klucze różnym odbiorcom i nadać im różne uprawnienia:
api:
authentication:
enabled: true
keys:
- name: "website"
key: "klucz-dla-strony"
permissions:
- "listings.read"
- "categories.read"
- "stats.read"
- "history.read"
- "players.read"
- name: "discord-bot"
key: "klucz-dla-bota"
permissions:
- "listings.read"
- "stats.read"Zalety osobnych kluczy:
- limity zapytań liczone są per nazwa klucza, więc bot nie zje limitu strony,
- gdy jeden klucz wycieknie, unieważniasz tylko jego,
- w logach widać, kto co odpytuje.
Generowanie dobrego klucza
Klucz to zwykły ciąg znaków — im dłuższy i bardziej losowy, tym lepiej. Nie wymyślaj go z głowy.
# PowerShell
-join ((48..57) + (65..90) + (97..122) | Get-Random -Count 48 | % {[char]$_})# Linux / macOS
openssl rand -hex 32Zasady higieny
- Nie commituj klucza do repozytorium.
- Nie wklejaj go w zgłoszeniach ani na zrzutach ekranu.
- Nie umieszczaj go w kodzie wykonywanym w przeglądarce — na stronie w Next.js klucz
zostaje po stronie serwera, nigdy w zmiennej
NEXT_PUBLIC_*. - Nie loguj go.
logging.requestsnie zapisuje kluczy, ale twoje własne proxy może.
CORS
CORS decyduje, które strony mogą odpytywać API z poziomu przeglądarki.
api:
cors:
enabled: true
allowed-origins:
- "https://rynek.twojadomena.pl"
- "http://localhost:3000"
allowed-headers:
- "Content-Type"
- "Accept"
- "X-API-Key"
- "Authorization"
allowed-methods:
- "GET"
- "OPTIONS"| Zasada | Dlaczego |
|---|---|
| Origin to schemat + domena + port | https://example.com ≠ http://example.com |
| Bez ukośnika na końcu | https://example.com/ nie zadziała |
| Każda subdomena osobno | www.example.com i example.com to dwa różne originy |
Nigdy * na produkcji | Otwiera API dla dowolnej strony w internecie |
localhost przy pracy nad stroną
Dopóki budujesz stronę lokalnie, trzymaj http://localhost:3000 na liście. Przy
wdrożeniu na produkcję możesz go usunąć — albo zostawić, jeśli nadal rozwijasz.
Limity zapytań
| Rodzaj | Limit domyślny | Liczony per |
|---|---|---|
| Bez klucza | 120 / min | Adres IP |
| Z kluczem | 300 / min | Nazwa klucza |
Klient dostaje nagłówki informacyjne przy każdej odpowiedzi:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287Po przekroczeniu limitu odpowiedź to 429 z nagłówkiem Retry-After.
Błędy uwierzytelniania
{
"error": {
"code": "LISTING_NOT_FOUND",
"message": "Listing does not exist.",
"status": 404
}
}| Kod HTTP | Znaczenie |
|---|---|
400 | Błędne parametry zapytania |
401 | Brak klucza albo klucz nieznany |
403 | Klucz poprawny, ale bez wymaganego uprawnienia |
404 | Zasób nie istnieje |
429 | Przekroczony limit zapytań |
500 | Błąd po stronie mostu |
503 | Rynek chwilowo niedostępny |
Odpowiedzi błędów nie zawierają stack trace — szczegóły lądują w logu serwera, a nie u klienta.