[Intum Dev](https://intum.dev.md) / [Technologia](https://intum.dev/technologia.md)

# [Jak projektować klucze API](https://intum.dev/technologia/jak-projektowac-klucze-api.md)

## Budowa klucza API

Klucz API to ciąg znaków składający się z kilku części, z których każda ma swoją rolę.

### Prefiks

Prefiks to jawna metadana na początku klucza - mówi skąd pochodzi. Stripe ma `sk_live_` i `sk_test_`, GitHub `ghp_`, OpenAI `sk-`, Slack `xoxb-`, Intum `intm_`.

Prefiks nie jest sekretem i nie musi nim być. Bezpieczeństwo klucza opiera się na entropii losowej części, nie na ukryciu pochodzenia. Wiedza że klucz należy do twojego serwisu nic nie daje atakującemu jeśli reszta ma wystarczającą losowość.

Praktyczne korzyści prefiksu:

- Narzędzia jak GitHub secret scanning, gitleaks, trufflehog mogą automatycznie rozpoznać wyciekły klucz i powiadomić dostawcę
- Developer widząc klucz od razu wie do jakiego serwisu należy i czy to produkcja czy test
- Możesz rozróżnić typy kluczy - publiczny vs prywatny, read-only vs full-access

Wybierając prefiks użyj czegoś specyficznego dla siebie - skrótu nazwy firmy/produktu, np. `koa_` dla "Koala". Nie ma centralnego rejestru, ale [lista partnerów GitHub secret scanning](https://docs.github.com/en/code-security/secret-scanning/introduction/supported-secret-scanning-patterns) pozwala sprawdzić czy prefiks nie koliduje z istniejącymi.

### Losowa część

Serce klucza - ciąg losowych bajtów zakodowany jako hex lub base64. Minimum 32 znaki hex (128 bitów entropii) to rozsądna wartość. Generuj kryptograficznie bezpiecznym generatorem (`crypto.randomBytes`, `SecureRandom`).

### Checksum (opcjonalnie)

Kilka znaków na końcu klucza wyliczanych z reszty - pozwala na szybką walidację formatu zanim w ogóle odpytasz bazę. Działa jak cyfra kontrolna w numerze PESEL - tani filtr przed droższą operacją.

W praktyce: bierzesz prefiks + losowy ciąg, przepuszczasz przez SHA-256 (albo CRC32), bierzesz pierwszych 6 znaków wyniku i doklejasz po separatorze. Przy walidacji powtarzasz obliczenie i porównujesz.

Czy to konieczne? Nie, większość API (Twilio, SendGrid, AWS) tego nie robi. Ma sens przy dużym ruchu gdy chcesz tanio odrzucać śmieciowe requesty. Przy mniejszej skali to taki trochę ekscentryczny bonus - miło mieć, ale aplikacja bez tego nie ucierpi.

### Przykładowa struktura

```
myapp_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6_x8f2a1
│       │                                    │
prefiks  losowa część (32+ znaków)            checksum
```

## Przechowywanie kluczy

Klucz API traktuj jak hasło - **nie przechowuj go w plain text**. W bazie trzymaj hash (SHA-256 wystarczy, bcrypt niepotrzebny bo klucze mają wysoką entropię). Użytkownikowi pokaż klucz tylko raz, przy tworzeniu. Po tym masz już tylko hash i nie da się go odtworzyć.

## Hashowanie dla routingu (multi-tenant)

W systemach z shardingiem baz danych trzeba szybko ustalić do którego sharda skierować request na podstawie klucza. Kilka podejść:

- Pełny SHA-256 mapowany na ID konta - działa, ale hash jest duży
- Prefiks firmy w kluczu - szybkie mapowanie, ale ujawnia strukturę konta
- SHAKE-256 (wariant SHA-3) - generuje hash o dowolnej długości bez przycinania pełnego hasha. 10 znaków base64url daje ~72 biliony możliwości i praktycznie zerowe ryzyko kolizji. Indeksy B-Tree w PostgreSQL radzą sobie z tym dobrze

Ciekawostka: kodowanie Base-62/Base-70 przez BigInt w JavaScripcie okazuje się zaskakująco wolne - arytmetyka o dowolnej precyzji i wielokrotne dzielenia generują duży narzut. Bezpośrednie porównywanie stringów hashów jest szybsze.

## Rejestracja w GitHub secret scanning

GitHub automatycznie skanuje publiczne repozytoria w poszukiwaniu wyciekłych sekretów. Możesz dołączyć do programu jako dostawca - nie ma wymogu co do wielkości firmy. Cały proces opisany jest w [dokumentacji GitHub secret scanning partner program](https://docs.github.com/en/code-security/secret-scanning/secret-scanning-partner-program/secret-scanning-partner-program).

Co trzeba zrobić:

1. Napisz na secret-scanning@github.com
2. Przygotuj wyrażenie regularne matchujące twoje klucze (prefiks + format)
3. Postaw publiczny HTTP endpoint który przyjmie webhooka od GitHuba
4. Zaimplementuj weryfikację podpisu i automatyczne unieważnianie wyciekłych kluczy

Gdy GitHub znajdzie klucz pasujący do twojego wzorca w publicznym repo, wysyła webhooka. Ty decydujesz czy unieważnić klucz, wydać nowy, czy powiadomić użytkownika.

Nawet jeśli nie masz jeszcze zasobów na budowanie tego endpointu - warto mieć unikalny prefiks od początku. Integrację z GitHubem możesz dodać później.

## Podsumowanie

Minimum: prefiks + losowa część + hashowanie przy zapisie. Checksum i rejestracja w GitHub to kolejne kroki gdy serwis dojrzeje. Najważniejsze to nie wymyślać koła od nowa w kwestii losowości i nie przechowywać kluczy w plain text.