Przejdź do głównej zawartości

Auth — API key

Wszystkie endpointy /api/v1/clinic/* wymagają API key Bearer z odpowiednim scope. Klucze są generowane per klinika w panelu Klinika → API Keys.

Format klucza​

pk_live_XXXXXXXX_<secret>
└──┬───┘ └──┬───┘ └──┬───┘
│ │ │
│ │ └─ 32-znakowy losowy secret (verify argon2)
│ └─ 8-znakowy publiczny prefix (lookup w bazie + audit log)
└─ environment marker (zawsze `pk_live_`)
  • Prefix widoczny w audit logu, panelu klinki, error messages
  • Secret — zhashowany argon2 w bazie, plaintext widzisz tylko raz przy create
  • Klucz testowy (pk_test_*) — nie zaimplementowane w MVP; użyj dev env

Wysyłanie klucza​

W headerze Authorization:

POST /api/v1/clinic/doctors HTTP/1.1
Host: api.pandoktorek.pl
Authorization: Bearer pk_live_XXXXXXXX_<secret>
Content-Type: application/json

:::warning NIE w URL Klucze NIGDY w query params (?api_key=...). To naruszenie G-AUTH-004 — klucze trafiają do logów serwerów / proxy / browser history. :::

Scopes​

Klucz dostaje listę scopes przy create. Każdy endpoint wymaga konkretnego scope — 401 jeśli brak.

ScopeEndpoints
doctors:writePOST /api/v1/clinic/doctors
services:writePOST /api/v1/clinic/services
slots:writePOST /api/v1/clinic/slots, DELETE /api/v1/clinic/slots/{external_id}
bookings:read(Faza 2) — pull rezerwacji ze stanem
webhooks:manage(Faza 2) — CRUD webhook subscriptions przez API

Zasada minimum: generuj klucz tylko z tymi scope'ami, które są ci potrzebne. Push slotów = klucz tylko z slots:write. Pełen ingest = trzy scope'y.

Lifecycle​

Generate​

Panel → API Keys → Nowy klucz
└─► nazwa (do identyfikacji)
└─► scopes (lista checkbox)
└─► [Zapisz]
└─► WYŚWIETL plaintext (`pk_live_XXX_secret`) — TYLKO RAZ
└─► copy to clipboard
└─► zapisz w secrets manager / .env / vault

Revoke​

Panel → API Keys → klucz → Revoke. Status revoked_at != NULL → kolejne requesty zwracają 401. Aktywne sesje webhook delivery nie są przerywane — osobny system.

Rotation​

Brak auto-rotation w MVP. Best practice ręczna rotacja co 90 dni:

  1. Generuj nowy klucz z tymi samymi scopes
  2. Update .env w swoim systemie + redeploy
  3. Verify że requests idą z nowym kluczem (audit log → filter prefix)
  4. Revoke stary

last_used_at na liście kluczy pomaga wykryć martwe klucze (G-DEV — security panel flag'uje klucze niewykorzystane >90 dni jako "dormant").

Bezpieczeństwo​

RegułaStatus w MVP
Plaintext widoczny tylko raz przy create✅
argon2 hash w DB✅
Per-key scopes✅
Per-key audit log (last_used_at)✅
Rate limit per klucz (10000 req/dobę)✅
Authorization: Bearer header only (NIE URL)✅
Block po subscription.past_due >7 dni✅ (G-FIN-004)
Auto-rotation❌ (Faza 2)
Webhook signing key (osobny od API key)✅ — generowany per subscription

Błędy auth​

StatusDetailCo robić
401Wymagana autoryzacja API keyBrak headera Authorization
401Nieprawidłowy format klucza APIKlucz nie zaczyna się od pk_live_ lub ma zły format
401Klucz API nieprawidłowy lub wycofanyKlucz revoked, expired albo secret się nie zgadza
401Brak uprawnień (scope)Klucz nie ma wymaganego scope dla tego endpointu
402Subskrypcja kliniki została anulowanaStripe billing — clinic_admin musi reaktywować
402Płatność za subskrypcję zaległa >7 dnipast_due grace period minął
429Rate limit exceeded (X req/dobę)Wyczerpałeś dobową pulę — patrz rate limits

→ Wszystkie kody błędów