tamtamp/oauth2-server-bundle
Symfony bundle for running an OAuth2 authorization server in your app: it handles grant flows and access token issuing so you can protect APIs without building the protocol yourself. Early-stage project with minimal adoption so far.
Reality check first: tamtamp/oauth2-server-bundle is a Symfony bundle, not a Laravel package. It will not install or boot in a Laravel app — it depends on symfony/framework-bundle, symfony/security-bundle, Doctrine ORM, and the Symfony DI container. If you are working in Laravel, this package is only useful to you in two ways: (a) as a reference for how league/oauth2-server is wired up, and (b) if you also maintain Symfony services. The Laravel-native equivalent is laravel/passport, which wraps the same underlying library (league/oauth2-server).
Where to look first:
league/oauth2-server (AuthorizationServer, ResourceServer, GrantType, ClientRepository, AccessTokenRepository, ScopeRepository). Everything the bundle does is glue around that library.config/packages/*oauth2*server.yaml in a Symfony app — the bundle's configuration tree (authorization_server, resource_server, grants, scopes, persistence) is where the day-to-day behavior lives.Client, AccessToken, RefreshToken, AuthCode, Scope) — you map these or extend them into your app.Minimal Symfony setup flow (if you are on Symfony):
composer require tamtamp/oauth2-server-bundle
# register the bundle in config/bundles.php
# generate keypair + encryption key
openssl genrsa -out var/oauth-private.key 2048
openssl rsa -in var/oauth-private.key -pubout -out var/oauth-public.key
php -r "echo base64_encode(random_bytes(32));" # encryption_key
Then configure the authorization and resource servers, create the persistence entities, run migrations, and wire the OAuth2 firewall endpoints (/token, /authorize) plus a resource-server firewall for your API routes.
First use case: pick the grant that matches your product. For an API consumed by first-party mobile/JS clients, use Authorization Code + PKCE. For service-to-service, use Client Credentials. Do not use the Password grant for anything new — the library deprecates the pattern and it bakes bad UX into your mobile app.
In Laravel terms, the first use case is: Passport::tokensCan([...]) defines scopes, php artisan passport:client creates a client, and the auth:api guard resolves the resource server — the same conceptual objects, different package.
Split your two servers. The bundle distinguishes the authorization server (issues tokens: /token, /authorize) from the resource server (validates tokens on your API). Keep them behind separate Symfony firewalls with separate security configs. This mirrors Passport::actingAs() vs. the auth:api middleware in Laravel — mixing them is how you end up accidentally trusting tokens from your own authorization endpoint for scopes they were never meant to carry.
Grants are toggles. Configure only the grants you actually expose:
authorization_code (add PKCE) — third-party or SPA/mobile clientsclient_credentials — machine-to-machinerefresh_token — always pair with authorization_codepassword — avoidScope discipline. Define scopes as configuration, validate them on the ScopeRepository, and enforce them at the resource server (the equivalent of Laravel's ->middleware('scope:orders.read')). Never trust a client-requested scope without intersect-with-config.
Persistence via Doctrine mapping. Use the bundle's entities as mapped superclasses (or reference them directly) and extend your User entity with the user trait / OAuth2UserInterface. Then run migrations. This is the most error-prone part of the setup because Symfony's Doctrine mapping wants explicit #[ORM\Entity] attributes and inheritance config; mismatches show up as silent empty token lookups, not exceptions.
Consent and user resolution are events. The bundle exposes AuthorizationRequestResolveEvent (to render/approve consent and return the user id) and UserResolveEvent (to map the user during password/user resolution). Do consent here — do not try to shoehorn the authorize page into a controller.
Token issuance/validation services. Inject the authorization server service to issue tokens and the resource server to validate Authorization: Bearer … headers. The bundle ships authenticators/guards that handle the HTTP layer for you.
CLI for provisioning. Use the bundle's console commands to create clients and scopes rather than hand-editing the database — the equivalent of php artisan passport:client --client and Passport::tokensCan.
Testing. Hit the /token endpoint with a real client via the bundle's test setup, then assert on the resource-server response. In Laravel, Passport::actingAs($user, ['scope']) is the shortcut you would reach for — the bundle has no comparable ergonomic, so expect to boot the Symfony kernel in tests.
trikoder/oauth2-bundle. Do not adopt it for new work. If you need Symfony OAuth2, use the upstream trikoder/oauth2-bundle (or league/oauth2-server directly). If you need Laravel, use laravel/passport — it tracks league/oauth2-server releases and is maintained.composer.json (league/oauth2-server ^8, Symfony 5.x/6.x, PHP 7.4–8.1). Expect breakage on Symfony 7 / PHP 8.3+ — the bundle predates both.encryption_key (base64, 32 bytes) protects authorization codes; the RSA keypair signs/validates access tokens. Rotating either invalidates in-flight tokens — plan rotation windows.AccessTokenRepository isn't finding tokens, check whether you configured resource-server public key verification or DB lookup.#[ORM\Entity], wrong inheritance type, or forgetting accessToken/refreshToken relations yields "invalid_grant" and empty token lists with no stack trace. Verify with a manual SELECT before assuming the grant logic is wrong.League\OAuth2\Server\Exception\OAuthServerException and log getHint()/getErrorType() — the Symfony profiler does not surface OAuth errors usefully. invalid_client, invalid_grant, invalid_scope map to distinct config problems./token and /authorize need CORS for browser clients and must be excluded from session-based CSRF in ways that differ from your normal Symfony firewall. Preflight OPTIONS on /token is a classic missing rule.Authorization headers, and scrub them from Symfony's request/response logging.GrantTypeInterface), custom ResponseType, custom scope validation, and listeners on the resolve events. Keep these thin — the library's interfaces are stable; the bundle's DI wiring is not.How can I help you explore Laravel packages today?