Grzybcio Wiki

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żkaPo co
GET /api/v1/healthSprawdzenie, czy most żyje — przydatne do monitoringu
GET /api/docsDokumentacja w HTML-u
GET /api/openapi.jsonSpecyfikacja OpenAPI 3

Uprawnienia

Każdy klucz ma własną listę uprawnień. Klucz bez danego uprawnienia dostanie 403.

Publiczne (dostępne w v1)

UprawnienieOtwiera
listings.readOferty, pojedyncza oferta, dane serwera, SSE
categories.readKategorie
stats.readStatystyki
history.readHistoria transakcji i wykresy cen
players.readProfile graczy, oferty gracza, lista sprzedawców

Zarezerwowane (w v1 zawsze odrzucane)

UprawnienieZachowanie w v1
listings.write403 WRITE_NOT_ENABLED
transactions.write403 WRITE_NOT_ENABLED
admin403 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:

plugins/GrzybcioRynekWeb/config.yml
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 32

Zasady 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.requests nie 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"
ZasadaDlaczego
Origin to schemat + domena + porthttps://example.com ≠ http://example.com
Bez ukośnika na końcuhttps://example.com/ nie zadziała
Każda subdomena osobnowww.example.com i example.com to dwa różne originy
Nigdy * na produkcjiOtwiera 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ń

RodzajLimit domyślnyLiczony per
Bez klucza120 / minAdres IP
Z kluczem300 / minNazwa klucza

Klient dostaje nagłówki informacyjne przy każdej odpowiedzi:

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287

Po 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 HTTPZnaczenie
400Błędne parametry zapytania
401Brak klucza albo klucz nieznany
403Klucz poprawny, ale bez wymaganego uprawnienia
404Zasób nie istnieje
429Przekroczony limit zapytań
500Błąd po stronie mostu
503Rynek chwilowo niedostępny

Odpowiedzi błędów nie zawierają stack trace — szczegóły lądują w logu serwera, a nie u klienta.

Na tej stronie