silasjoisten/sonata-oauth2-login-bundle
Symfony bundle that adds OAuth2 login to Sonata Admin, letting users authenticate through external providers instead of local credentials. Configure your OAuth2 provider and integrate single sign-on into the Sonata admin panel with minimal setup.
This is a Symfony bundle (not Laravel) that bolts OAuth2 login onto a Sonata Admin panel — it lets admins sign in with Google/GitHub/Azure/etc. instead of, or alongside, the standard Sonata login form.
composer require silasjoisten/sonata-oauth2-login-bundle:^6.1Sonata\OAuth2LoginBundle\SonataOAuth2LoginBundle in config/bundles.php@SonataOAuth2LoginBundle/Resources/config/routing.yaml) in config/routes.yamlproviders: block to config/packages/sonata_oauth2_login.yaml with the client credentials, scopes, and an absolute redirect_uri pointing at the bundle's check routesecurity.yaml, run bin/console debug:router | grep -i oauth2 to confirm the redirect/check routes are registeredFirst use case: replace the Sonata login page with a "Sign in with Google" button for a single provider, with the OAuth callback resolving to an existing Sonata user by email. Get that one-provider flow working end to end before adding a second provider or auto-provisioning.
Look first at: bin/console config:dump-reference sonata_oauth2_login — the README lags behind the config tree, and this is the authoritative list of keys for the installed version.
One provider key = one route pair. Each entry under providers: generates its own redirect and check route keyed by name (google, github, …). Adding a provider is config-only — no controller code — so model the provider list as environment-specific config rather than hardcoding it.
Keep the callback public, keep /admin protected. The OAuth redirect/check routes must be reachable anonymously, while /admin stays behind ROLE_ADMIN/ROLE_SONATA_ADMIN. Test the access_control ordering, since Symfony matches rules top-down and a broad ^/ rule will swallow the callback.
Coexist with form login. The usual pattern is a dual login page: the Sonata form for local/break-glass accounts, plus OAuth buttons. Keeping at least one password-based super-admin is worth the friction — it is your recovery path if a provider tenant or client secret is misconfigured.
Separate OAuth apps per environment. admin.example.com in prod, admin.staging.example.com in staging, localhost:8000 in dev. Put client IDs/secrets in .env and reference them via %env(...)% rather than committing YAML with secrets.
Provisioning is the real design decision. Decide up front whether OAuth users must already exist (lookup by email, reject unknown) or are auto-created on first login. For an admin panel, the lookup-only path is usually correct: it means an attacker who controls an account at the IdP still cannot get into Sonata unless you pre-created the user. If you do auto-create, gate it on a verified email domain and assign the most limited role that renders the dashboard.
Never derive admin roles from IdP claims. Map OAuth identity → local user → local roles. Group/claim mapping is tempting but hands your authorization model to whoever administers the customer's Google Workspace.
Customize via decoration, not forks. The user resolution/creation step and the login templates are the two extension points you will actually need. Decorate the relevant service (or override the template) in services.yaml so security patches to the bundle stay mergeable.
Testing. For feature tests, stub the HTTP client used by the underlying OAuth2 client so the token exchange returns a canned identity, then assert the resulting authenticated user and roles. Asserting on the redirect URL alone misses the provisioning logic, which is where bugs live.
redirect_uri mismatch is the #1 failure. Scheme, host, port, trailing slash, and path must match the provider console byte-for-byte. The provider returns a generic redirect_uri_mismatch before your app logs anything — always compare the URL in the browser's address bar against the console entry first.http:// from X-Forwarded-* unless you configure framework.trusted_proxies and trusted_headers. Symptom: infinite bounce between provider and app with no error.^2.0 support. This is a minor version bump with a dependency removal. If you are still on Twig 2 (or on a Symfony version whose constraints require it), Composer will silently resolve you to 6.0.x — composer why-not silasjoisten/sonata-oauth2-login-bundle 6.1.0 will show the conflicting package. Twig 2 is EOL, so plan the upgrade to Twig 3 rather than pinning the bundle.user:email scope and handle the /user/emails endpoint. If you key users by email, this silently fails for a subset of accounts.bin/console cache:clear in the right --env before concluding that a config key "isn't being picked up".debug:router → debug:config sonata_oauth2_login → check the profiler's security panel for the token/roles actually produced → then the provisioning service. Most "login loops" are a firewall ordering issue or an exception swallowed inside the check controller, which the profiler exposes but the browser does not.^6.1 in composer.json and read the changelog before any major. Security-adjacent bundles are a poor place to float on *.How can I help you explore Laravel packages today?