Download the PHP package musikhood/auth-client-bundle without Composer
On this page you can find all versions of the php package musikhood/auth-client-bundle. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Informations about the package auth-client-bundle
auth-client-bundle
Symfony bundle dla mikroserwisów, które delegują uwierzytelnianie do zewnętrznego auth servera (editor_v3) i wystawiają front-endowi spójny kontrakt oparty na ciasteczkach HttpOnly.
Bundle obsługuje całą warstwę HTTP — endpointy /api/login, /api/logout,
/api/token/refresh, /api/v1/user/me — walidację JWT/JWKS, kontrakt
ciasteczek (BEARER + refresh_token, oba HttpOnly), lokalną kopię
użytkownika z lazy upsert oraz listener z circuit breakerem, który co 30 s
weryfikuje sesję w auth serverze.
Front nigdy nie widzi JWT. Używa withCredentials: true plus interceptora
axiosa, który na 401 woła /api/token/refresh. Front napisany przeciw
samemu auth serverowi działa bez zmian z dowolnym mikroserwisem
korzystającym z tej paczki.
Wymagania
- PHP
>=8.2 - Symfony
^6.4 || ^7.0(security-bundle, framework-bundle, http-client) - ORM po stronie konsumenta (zalecany Doctrine) — paczka dostarcza tylko
interfejsy (
PanelUserInterface,PanelUserRepositoryInterface); konkretną encję i repozytorium tworzy konsument.
Instalacja
1. Dodaj endpoint Symfony Flex
Bundle dostarcza recipe Symfony Flex, które konfiguruje bundles.php,
config/packages/auth_client.yaml, import tras i zmienne środowiskowe.
Recipe siedzi w
musikhood/symfony-recipes.
Dodaj endpoint do composer.json w aplikacji konsumenta (jednorazowo):
Zostaw flex://defaults po swoim endpoincie — bez tego nie będą działać
oficjalne recipes Symfony (Doctrine, Mailer itd.).
2. Zainstaluj paczkę
Flex zrobi automatycznie:
- zarejestruje
Musikhood\AuthClient\AuthClientBundlewconfig/bundles.php - utworzy
config/packages/auth_client.yamlz szablonem na zmienne środowiskowe - utworzy
config/routes/auth_client.yamlimportujący trasy paczki - doda klucze
AUTH_*do.env - wyświetli listę kroków, które musisz dokończyć ręcznie (sekcja 3 niżej)
Jeśli composer require nie pokaże komunikatu post-install, prawdopodobnie:
- Flex nie jest zainstalowany w konsumencie (
composer require symfony/flex) - brakuje konfiguracji endpointu z kroku 1
- paczka była już zainstalowana wcześniej — zrób
composer remove musikhood/auth-client-bundle && composer clear-cachei powtórzrequire
3. Kroki, które musisz wykonać ręcznie
Recipe robi tylko to, co bezpiecznie da się zautomatyzować. Pięć rzeczy wymaga jeszcze Twojej ręki — wszystkie dotykają miejsc specyficznych dla projektu, których recipe nie może zgadnąć.
3.1. Ustaw zmienne środowiskowe
W .env.local (albo Twoim secrets manager):
AUTH_COOKIE_SECURE ustaw na 1 w produkcji (HTTPS), 0 tylko dla
lokalnego deva po HTTP.
3.2. Stwórz encję User
Paczka nigdy nie pisze do tabeli użytkowników — to robi konsument.
Zaimplementuj Musikhood\AuthClient\Contract\PanelUserInterface
(referencja: docs/example-entity.php):
Jeśli używasz innej lokalizacji niż src/Entity/ (np. DDD ze strukturą
src/Domain/User/Entity/User.php), umieść klasę gdziekolwiek — paczka
patrzy tylko na kontrakt PanelUserInterface.
3.3. Stwórz UserRepository
Zaimplementuj Musikhood\AuthClient\Contract\PanelUserRepositoryInterface
i powiąż go z interfejsem przez atrybut #[AsAlias]. Dzięki temu nie
musisz nic dopisywać do services.yaml — Symfony sam podepnie repo pod
interfejs.
Referencja: docs/example-repository.php.
Atrybut #[AsAlias] wymaga Symfony 6.1+. Jeśli z jakiegoś powodu wolisz
mapowanie w YAML-u, zamiast atrybutu dodaj do config/services.yaml:
Paczka rozwiązuje PanelUserRepositoryInterface z kontenera DI — bez
jednego z tych dwóch wariantów authenticator i MeController wywalą się
przy starcie z błędem "Cannot autowire".
3.4. Skonfiguruj security
Recipe nie modyfikuje config/packages/security.yaml, bo większość
projektów ma już własny firewall i auto-merge byłby ryzykowny. Skopiuj ten
fragment ręcznie:
3.5. Stwórz tabelę w bazie
Albo skopiuj docs/example-migration.sql
prosto do swojego narzędzia migracji, albo wygeneruj migrację z encji:
Tabela potrzebuje kolumn: id (UUID), email (unique), display_name,
roles_for_panel (JSON), disabled (bool), last_synced_at. Pełny
mapping w docs/example-entity.php.
Synchronizacja z auth serverem
Auth server jest jedynym źródłem prawdy dla ról, displayName i flagi
disabled. Lokalna kopia użytkownika w mikroserwisie jest aktualizowana
w dwóch momentach:
- Pierwszy kontakt z userem (bootstrap) — gdy authenticator widzi zalogowanego usera, którego jeszcze nie ma w lokalnej tabeli, paczka tworzy lokalną kopię z claimów świeżego JWT (email, displayName, role per-panel). To jednorazowe — przy każdym kolejnym requeście tego usera authenticator NIE rusza już lokalnej kopii.
- Co ~30s na żądanie zalogowanego usera —
AuthValidationListenerwoła/api/v1/user/mena auth serverze i synchronizuje pełen payload (email, displayName, role per-panel, flagadisabled). To jest jedyna ścieżka aktualizacji istniejącej kopii. Krok pomijany jeśli wynik z poprzedniego wywołania jeszcze leży w cache (validation_cache_ttl, domyślnie 30s).
W szczególności paczka nie używa lokalnej flagi isDisabled() do
podejmowania decyzji o autoryzacji. Gating disabled userów leci
wyłącznie przez /me — co znaczy że:
- Po zablokowaniu konta w panelu admin auth servera użytkownik
zostanie wylogowany w czasie max.
validation_cache_ttlsekund. - Po odblokowaniu konta użytkownik znowu działa bez ponownego
logowania (jeśli JWT jest jeszcze ważny — w innym przypadku front
interceptor zrobi
/api/token/refreshi auth server wystawi nowy). - Po zmianie ról / displayName w panelu admin nowe wartości pojawią się
w lokalnej kopii w czasie max.
validation_cache_ttlsekund. Auth server NIE podbijatokenVersionprzy tych zmianach — istniejące JWT zostają ważne, propagacja idzie przez/me.
Lokalne pole disabled w encji konsumenta służy tylko do wyświetlenia
(np. w panelu zarządzania userami w mikroserwisie). Aktualizowane
automatycznie przez syncFromMe().
Webhook inwalidacji (0s revocation)
Od wersji 0.3.0 paczka nasłuchuje webhooków od auth servera i skraca czas
rewokacji sesji z ~30s (poll /me opisany wyżej) do setek milisekund.
Jak to działa. Po inwalidacji usera (zablokowanie konta, zmiana hasła,
odebranie dostępu do panelu) auth server podbija tokenVersion i pushuje
podpisany webhook na endpoint paczki
POST /api/auth-client/webhook/user-invalidated. Paczka weryfikuje podpis
(WebhookJwtValidator, ten sam JWKS co user JWT), zapisuje nową tokenVersion
w cache (UserTokenVersionStore) i kasuje cache walidacji usera. Przy
najbliższym requeście tego usera JwtCookieAuthenticator porównuje ver
z jego JWT z zapisaną wartością i odrzuca stary token (401) bez czekania na
poll /me.
Co musisz zrobić.
- Dodaj
PUBLIC_ACCESSdla ścieżki webhooka wsecurity.yaml(patrz krok „Skonfiguruj security" powyżej). Webhook autoryzuje się sam podpisem JWT auth servera — to model jak weryfikacja podpisu webhooków Stripe/GitHub, nie dziura w security. - W panelu admin auth servera ustaw pole „Webhook URL" dla swojego panelu na
bazowy URL backendu mikroserwisu (np.
https://pim.vitkac.com). Auth server sam dokleja ścieżkę/api/auth-client/webhook/user-invalidated. - Upewnij się, że
cache.appjest skonfigurowane (Redis zalecany — stan musi być współdzielony między procesami workerów i przeżyć restart).
Nie musisz nic zmieniać w swojej encji. tokenVersion żyje w cache PSR,
nie w kolumnie DB — webhook może przyjść nawet dla usera, którego mikroserwis
jeszcze nie zna lokalnie. Reset cache (flush Redisa) jest nieszkodliwy: brak
wpisu = pass, a poll /me dogoni inwalidację w ~30s (fallback).
Monolog tip. Jeśli używasz fingers_crossed z action_level: error
(typowy prod default Symfony), logi webhook.received (poziom info) będą
buforowane i tracone, gdy webhook kończy się 200 OK — bufor jest zrzucany
tylko gdy w tym samym requeście wystąpi error. Żeby widzieć je w
kubectl logs, dodaj osobny handler/channel ze stream do php://stderr
na poziomie info.
Kontrakt z front-endem
Front nigdy nie widzi JWT. Wymaga:
axios.defaults.withCredentials = true(lub równowartośćfetchzcredentials: 'include')- na
401z dowolnego/api/*:POST /api/token/refresh, potem retry - na
401z/api/token/refresh: czyść lokalny stan UI, redirect do logowania - na
403z dowolnego/api/*(brak dostępu do tego panelu, sesja ŻYJE): NIE refreshuj, NIE czyść ciasteczek, NIE broadcastuj wylogowania — pokaż ekran „brak dostępu" / login. Ciasteczka SSO zostają ważne na panelach, do których user MA dostęp. Paczka@musikhood-dev/auth-clientklasyfikuje to jakoPanelAccessDeniedErrorautomatycznie.
Kontrakt 401 vs 403: 401 = sesja martwa (globalne wylogowanie po nieudanym refreshu), 403 = brak dostępu do panelu (sesja żyje, bez czyszczenia).
To ten sam kontrakt co przy gadaniu wprost z auth serverem, więc istniejący front przesiada się na inny backend bez zmian.
Pełna konfiguracja
Wszystkie klucze z domyślnymi wartościami — ustawiasz je w
config/packages/auth_client.yaml. Recipe wgrywa tylko klucze wymagane
(cztery AUTH_* env-y plus cookie.secure); reszta poniżej ma sensowne
defaulty.
API token (autoryzacja maszynowa)
Drugi sposób autoryzacji obok ciasteczek — dla klientów server-to-server, które
nie mają sesji przeglądarkowej. Klient wysyła per-user-per-panel token w
nagłówku X-Api-Token (format mhpat_…), bez logowania, ciasteczek ani
refreshu.
ApiTokenAuthenticator reaguje tylko gdy nagłówek jest obecny, więc współistnieje
z JwtCookieAuthenticator w tym samym firewallu — bez nagłówka stary cookie flow
działa bez zmian. Token jest weryfikowany live przez introspekcję na auth serverze
(POST /api/auth/backend/api-token/verify) — paczka nie trzyma kopii, więc revoke
po stronie auth servera = natychmiastowa rewokacja (następny request → 401). Gdy
auth server jest niedostępny, authenticator robi fail-closed (401).
Role pochodzą z panelRoles introspekcji (z prefiksem ROLE_), tak samo jak przy
JWT — istniejące #[IsGranted('ROLE_PUBLISH')] działają bez zmian. Token jest
generowany / regenerowany / usuwany wyłącznie przez admina w panelu auth servera
(„niezmienny" = brak edycji wartości; zmiana = regeneracja, stary natychmiast
martwy).
Endpointy wystawiane przez paczkę
| Metoda | Ścieżka | Opis |
|---|---|---|
POST |
/api/login |
Wymienia {username, password} na ciasteczka BEARER + refresh_token. |
POST |
/api/logout (alias /api/token/invalidate) |
Czyści ciasteczka, unieważnia refresh token w auth serverze. |
POST |
/api/token/refresh |
Generuje nową parę ciasteczek z refresh tokena. |
GET |
/api/v1/user/me |
Zwraca dane zalogowanego użytkownika (id, email, displayName, roles, disabled). Czyta z lokalnej kopii — nie wymaga round-tripa do auth servera. |
POST |
/api/auth-client/webhook/user-invalidated |
Webhook inwalidacji usera (0s revocation). Autoryzacja podpisem JWT auth servera (nie user auth — wymaga PUBLIC_ACCESS w access_control). Patrz „Webhook inwalidacji". |
Licencja
MIT — patrz LICENSE.
All versions of auth-client-bundle with dependencies
ext-openssl Version *
firebase/php-jwt Version ^6.10 || ^7.0
psr/cache Version ^2.0 || ^3.0
psr/log Version ^2.0 || ^3.0
ramsey/uuid Version ^4.7
symfony/cache-contracts Version ^2.5 || ^3.0
symfony/config Version ^6.4 || ^7.0
symfony/dependency-injection Version ^6.4 || ^7.0
symfony/event-dispatcher Version ^6.4 || ^7.0
symfony/framework-bundle Version ^6.4 || ^7.0
symfony/http-client Version ^6.4 || ^7.0
symfony/http-client-contracts Version ^2.5 || ^3.0
symfony/http-foundation Version ^6.4 || ^7.0
symfony/http-kernel Version ^6.4 || ^7.0
symfony/routing Version ^6.4 || ^7.0
symfony/security-bundle Version ^6.4 || ^7.0
symfony/security-core Version ^6.4 || ^7.0
symfony/security-http Version ^6.4 || ^7.0
symfony/yaml Version ^6.4 || ^7.0