jostkleigrewe/lib-php-eurip-sso
A PHP library for integrating EURIP single sign-on (SSO) into your applications, with helpers for authentication flows and session handling to simplify adding SSO support to Laravel or plain PHP projects.
Minimum requirements are now PHP 8.4+ and Symfony 7.0+ / 8.0+ — verify your runtime and composer.json constraints before upgrading. This is a hard break from the 8.2 baseline.
First steps after composer update:
EuripSsoFacade, OidcController, OidcRouteLoader, all ::NAME event constants, OidcConstants::EVENT_*, and the service aliases (eurip_sso.claims, eurip_sso.auth, eurip_sso.api, eurip_sso.token_storage) are gone. Grep your codebase for these before running anything.config/services.yaml resource scanning, with scalar config injected through #[Autowire('%eurip_sso.param%')]. If you extended or overrode any bundle services manually, those wiring blocks are now stale.eurip:sso:cache-warmup early — it pre-fetches the discovery document and JWKS so your first login request isn't paying the latency and cache-priming cost.eurip:sso:test-connection to validate your IdP config before touching the UI. This is the fastest sanity check for a broken provider URL, client secret, or discovery mismatch.First real use case: hit your login route, confirm the callback lands, then check /auth/debug (new sensible default) to inspect the resolved discovery document, claims, and token state. In v0.3.0 that page is served by DiagnosticsController, split out from the old monolithic OidcController.
Inject FQCNs, not aliases. With the service aliases removed, day-to-day code becomes:
public function __construct(
private OidcClient $client,
private OidcAuthenticationService $auth,
) {}
OidcAuthenticationService now holds the login-initiation and callback-handling logic that used to live in the controller. If you were calling into controller internals (you shouldn't have been, but people do), move to this service.
Construct OidcClient through the factory. OidcClient::fromDiscovery() is removed. Use OidcClientFactory::create(), which now also builds the JwtVerifier and injects it as the 5th constructor argument. If you instantiate OidcClient directly anywhere, you must pass JwtVerifier explicitly — it is no longer optional-positioned before $logger.
Treat JwtVerifier as the JWT surface. JWKS preloading, cache fetch/invalidate, and hasJwksLoaded moved off OidcClient onto JwtVerifier. Wrap your own token-validation code around verifySignature(); it handles RS256 verification, cache TTL, and automatic key-rotation retry (invalidate → refetch → verify), so don't reimplement that retry loop.
Register events by class. Event listeners use #[AsEventListener] with no event: parameter — the event class is inferred from the __invoke() type hint. Any listener still referencing OidcConstants::EVENT_* or the removed ::NAME constants will silently stop firing. Same rule applies to the new OidcSessionChangedEvent.
Handle auth errors structurally. Catch OidcAuthenticationException and branch on the OidcErrorCode enum (INVALID_STATE, MISSING_CODE, TOKEN_EXCHANGE_FAILED, INVALID_ID_TOKEN, CLAIMS_VALIDATION_FAILED, PROVIDER_ERROR) rather than string-matching messages. This is the cleanest upgrade win — surface distinct UX for state expiry vs. provider outage.
Use the split controllers as extension points. AuthenticationController, ProfileController, DiagnosticsController, BackchannelLogoutController, and FrontchannelLogoutController are now separate. Override only what you need; do not subclass the old OidcController. Route names are unchanged (eurip_sso_login, eurip_sso_callback, eurip_sso_logout), so existing path()/url() calls and redirects keep working.
Prefer #[Route] attributes with %parameter% placeholders. OidcRouteLoader is gone. If you were patching routes dynamically, move that into routes.* config keys — including the new routes.logout_confirm (default /auth/logout/confirm). Defaults for profile, debug, and test now exist, so drop overrides you only set to the old hardcoded values.
New CLI flows for ops and M2M. eurip:sso:device-login (RFC 8628), eurip:sso:client-credentials, and eurip:sso:introspect (RFC 7662) cover CLI login and machine-to-machine tokens without a browser. Wire client-credentials + introspect into scheduled jobs or service-to-service calls; use device-login for interactive CLI tooling.
Session monitoring is opt-in but cheap. Enable the IdP-side feature, then use sso_supports_session_management() to gate the UI and sso_session_management_config(interval) plus SessionMonitor.html.twig for polling. Listen for OidcSessionChangedEvent to react to session invalidation (e.g., forced logout, redirect to re-auth).
New Twig helpers reduce controller boilerplate. sso_is_authenticated(), sso_email(), sso_name(), sso_user_id(), sso_has_role(), sso_has_permission(), sso_has_group(), sso_claim('key', 'default'). Use sso_claim with a default for optional claims instead of null-checking in templates. The <twig:EuripSso:Logout /> component (requires symfony/ux-twig-component) gives you CSRF-protected logout with label, class, asLink, confirm props — replace hand-rolled logout forms.
Upgrade SsoClaims access. Where you previously pulled an array off the auth service, use the new SsoClaims DTO for structured claim access, or the Twig helpers for view-layer reads.
EVENT_* constants don't throw — listeners just never run. Audit every #[AsEventListener(event: ...)] and every string-based event dispatch.OidcConstants is now a final class, not an interface. Any implements OidcConstants will fatal at class-load. Remove it.JwtVerifier is the 5th parameter before $logger. Direct instantiation with positional args will break cryptically (type error on the logger slot). Use named arguments or the factory.OidcClient::__construct is not the recommended path. OidcClientFactory::create() is the supported entry point; it also wires the verifier correctly.create() and cache warmup share key logic. buildJwksCacheKey() is now public — if you namespace or version your cache keys, hook here so warmup and runtime agree. Mismatched keys mean warmup is wasted and you refetch on every request.controller.enabled, client_services.enabled, client_services.store_access_token, and the three authenticator.* path keys. Controllers and client services are always on now. Any %eurip_sso.*% placeholder referencing a removed key will fail container compilation — expect build-time errors, not runtime ones.routes.*. authenticator.callback_route, default_target_path, and login_path are gone; replicate behavior via routes.*. A missed migration here usually shows up as a redirect loop or a 404 after login rather than a clear error.authenticator.enabled is the only remaining toggle (default true). If you had layered toggles, collapse them.AuthenticationController fixed parse_url() return-type handling. If you had a custom referer workaround, remove it — leaving it in can produce double-validation or redirect loops behind proxies.vendor/autoload.php for tests rather than the parent project's. If you run its suite inside your app, autoload collisions or "class not found" for your app's tests are the symptom.JwtVerifier is framework-agnostic by design (PSR-18 HTTP, PSR-17 request factory, PSR-3 logger). You can reuse it outside the Symfony bundle — useful for standalone token validation scripts or queue workers.eurip:sso:test-connection for provider reachability → eurip:sso:cache-warmup for discovery/JWKS → /auth/debug for resolved claims → catch OidcAuthenticationException and log the OidcErrorCode. That ordering resolves most "SSO broke after deploy" tickets quickly.#[AsEventListener] on OidcSessionChangedEvent, and use SsoClaims/Twig helpers rather than reaching into services from templates.docs/FLOW-DIAGRAMS.md, docs/SESSION-MANAGEMENT.md, docs/DEVICE-CODE-FLOW.md, docs/M2M-AUTHENTICATION.md (German variants alongside). Read the flow diagrams first — they map the new controller split faster than the class list.How can I help you explore Laravel packages today?