### Install OAuth2 Server Bundle and Doctrine Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt Install the bundle and Doctrine for persistence using Composer. ```sh composer require league/oauth2-server-bundle composer require doctrine/doctrine-bundle doctrine/orm ``` -------------------------------- ### Install Development Dependencies Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/CONTRIBUTING.md Use Composer to download all necessary packages for developing the project. Ensure you have Composer 2+ installed. ```sh composer update --prefer-stable ``` -------------------------------- ### Implement Custom Redis Access Token Manager Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt Implement a custom persistence manager for access tokens using Redis. This example demonstrates saving and retrieving access tokens from Redis, leveraging its automatic key expiration. ```php redis->get("oauth2:access_token:{$identifier}"); return $data ? unserialize($data) : null; } public function save(AccessTokenInterface $accessToken): void { $ttl = $accessToken->getExpiry()->getTimestamp() - time(); $this->redis->setex( "oauth2:access_token:{$accessToken->getIdentifier()}", max($ttl, 1), serialize($accessToken) ); } public function clearExpired(): int { // Redis auto-expires keys, return 0 return 0; } } ``` ```yaml # config/packages/league_oauth2_server.yaml league_oauth2_server: persistence: custom: access_token_manager: App\Manager\RedisAccessTokenManager authorization_code_manager: App\Manager\RedisAuthorizationCodeManager client_manager: App\Manager\RedisClientManager refresh_token_manager: App\Manager\RedisRefreshTokenManager credentials_revoker: App\Service\RedisCredentialsRevoker ``` -------------------------------- ### MySQL Table Schema for Custom Persistence Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/using-custom-persistence-managers.md Example MySQL table schemas for implementing custom persistence managers. These include tables for access tokens, authorization codes, clients, and refresh tokens. ```sql CREATE TABLE `oauth2_access_token` ( `identifier` char(80) NOT NULL, `client` varchar(32) NOT NULL, `expiry` datetime NOT NULL, `userIdentifier` varchar(128) DEFAULT NULL, `scopes` text, `revoked` tinyint(1) NOT NULL, PRIMARY KEY (`identifier`), KEY `client` (`client`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `oauth2_authorization_code` ( `identifier` char(80) NOT NULL, `client` varchar(32) NOT NULL, `expiry` datetime NOT NULL, `userIdentifier` varchar(128) DEFAULT NULL, `scopes` text, `revoked` tinyint(1) NOT NULL, PRIMARY KEY (`identifier`), KEY `client` (`client`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `oauth2_client` ( `identifier` varchar(32) NOT NULL, `name` varchar(128) NOT NULL, `secret` varchar(128) DEFAULT NULL, `redirectUris` text, `grants` text, `scopes` text, `active` tinyint(1) NOT NULL, `allowPlainTextPkce` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`identifier`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `oauth2_refresh_token` ( `identifier` char(80) NOT NULL, `access_token` char(80) DEFAULT NULL, `expiry` datetime NOT NULL, `revoked` tinyint(1) NOT NULL, PRIMARY KEY (`identifier`), KEY `access_token` (`access_token`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``` -------------------------------- ### Implement Custom API Key Grant Type Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt Create a custom OAuth2 grant type by extending AbstractGrant and implementing GrantTypeInterface. This example shows an 'api_key' grant that validates an API key to authenticate users. ```php validateClient($request); $apiKey = $this->getRequestParameter('api_key', $request); $user = $this->apiKeyValidator->validateApiKey($apiKey); if (!$user) { throw OAuthServerException::invalidGrant('Invalid API key'); } $scopes = $this->validateScopes( $this->getRequestParameter('scope', $request, $this->defaultScope) ); $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getId(), $scopes); $responseType->setAccessToken($accessToken); return $responseType; } public function getAccessTokenTTL(): ?DateInterval { return new DateInterval('PT2H'); } } ``` ```yaml # config/services.yaml services: App\Grant\ApiKeyGrant: autoconfigure: true arguments: - '@App\Service\ApiKeyValidator' ``` -------------------------------- ### Device Code Verification Controller Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt Implement the device code verification UI controller for the device authorization flow. This controller handles GET and POST requests to verify user codes. ```php createFormBuilder() ->add('userCode', TextType::class, [ 'label' => 'Enter the code displayed on your device', 'attr' => ['placeholder' => 'XXXX-XXXX'], ]) ->getForm() ->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { try { $userCode = $form->get('userCode')->getData(); $deviceCode = $this->deviceCodeManager->findByUserCode($userCode); if (!$deviceCode) { throw OAuthServerException::invalidGrant('Invalid user code'); } $this->authorizationServer->completeDeviceAuthorizationRequest( $deviceCode->getIdentifier(), $this->getUser()->getUserIdentifier(), true ); $this->addFlash('success', 'Device authorized successfully!'); return $this->redirectToRoute('app_home'); } catch (OAuthServerException $e) { $this->addFlash('error', $e->getMessage()); } } return $this->render('device/verify.html.twig', [ 'form' => $form, ]); } } ``` -------------------------------- ### Grant Security Roles Based on Token Scopes (PHP) Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/basic-setup.md Users are granted roles like ROLE_OAUTH2_ after passing the OAuth2 firewall. This example uses the @IsGranted annotation to enforce a specific role. ```php /** * @IsGranted("ROLE_OAUTH2_EDIT") */ public function indexAction() { // ... } ``` -------------------------------- ### Enable League OAuth2 Server Bundle Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/index.md Add the bundle to your `config/bundles.php` file to enable it. ```php League\Bundle\OAuth2ServerBundle\LeagueOAuth2ServerBundle::class => ['all' => true] ``` -------------------------------- ### Run Test Suite Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/CONTRIBUTING.md Execute the entire test suite using Simple-PHPUnit. Ensure all tests pass to confirm the stability of your changes. ```sh vendor/bin/simple-phpunit ``` -------------------------------- ### Import Bundle Routes Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/index.md Configure your `config/routes.yaml` to import the bundle's routes. ```yaml oauth2: resource: '@LeagueOAuth2ServerBundle/config/routes.php' type: php ``` -------------------------------- ### Create OAuth2 Client (CLI) Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt Create OAuth2 clients using the console command with configurable redirect URIs, grant types, and scopes. Supports confidential, public, and PKCE clients. ```sh # Create a confidential client with auto-generated identifier and secret bin/console league:oauth2-server:create-client "My App" # Create client with specific identifier and secret bin/console league:oauth2-server:create-client "My App" my_client_id my_client_secret # Create client with redirect URIs and grant types bin/console league:oauth2-server:create-client "My App" \ --redirect-uri=https://myapp.com/callback \ --redirect-uri=https://myapp.com/callback2 \ --grant-type=authorization_code \ --grant-type=refresh_token \ --scope=email \ --scope=profile # Create a public client (no secret, for SPAs/mobile apps) bin/console league:oauth2-server:create-client "SPA App" --public # Create client allowing plain PKCE challenge method bin/console league:oauth2-server:create-client "Legacy App" --public --allow-plain-text-pkce ``` -------------------------------- ### Configure Bundle to Use Custom Managers Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/using-custom-persistence-managers.md Configure the OAuth2 Server Bundle to utilize your newly registered custom persistence managers. Specify the fully qualified class names for each manager. ```yaml league_oauth2_server: persistence: custom: access_token_manager: App\Manager\MyAccessTokenManager authorization_code_manager: App\Manager\MyAuthorizationCodeManager client_manager: App\Manager\MyClientManager refresh_token_manager: App\Manager\MyRefreshTokenManager credentials_revoker: App\Service\MyCredentialsRevoker ``` -------------------------------- ### Create an OAuth Server Event Listener Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/listening-to-league-events.md Implement a listener class to handle specific OAuth server events. Ensure the method signature matches the event's expected parameters. ```php [ []] Arguments: name The client name identifier The client identifier secret The client secret Options: --redirect-uri=REDIRECT-URI Sets redirect uri for client. Use this option multiple times to set multiple redirect URIs. (multiple values allowed) --grant-type=GRANT-TYPE Sets allowed grant type for client. Use this option multiple times to set multiple grant types. (multiple values allowed) --scope=SCOPE Sets allowed scope for client. Use this option multiple times to set multiple scopes. (multiple values allowed) --public Creates a public client (a client which does not have a secret) --allow-plain-text-pkce Creates a client which is allowed to create an authorization code grant PKCE request with the "plain" code challenge method ``` -------------------------------- ### Configure User Resolution Listener Service Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/password-grant-handling.md This YAML configuration registers the `UserResolveListener` as a service and tags it as an event listener for the `league.oauth2_server.event.user_resolve` event, injecting the necessary user provider and password hasher services. ```yaml App\EventListener\UserResolveListener: arguments: - '@security.user_providers' - '@security.password_hasher' tags: - { name: kernel.event_listener, event: league.oauth2_server.event.user_resolve, method: onUserResolve } ``` -------------------------------- ### Run Static Analysis Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/CONTRIBUTING.md Execute PHPStan to perform static analysis on the codebase. This helps identify potential bugs and code quality issues. ```sh vendor/bin/phpstan ``` -------------------------------- ### Request Access Token (Password Grant) Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt Authenticate users directly with username and password. Requires a UserResolveEvent listener to be configured. ```sh curl -X POST https://example.com/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=password" \ -d "client_id=my_client_id" \ -d "client_secret=my_client_secret" \ -d "username=user@example.com" \ -d "password=user_password" \ -d "scope=email profile" ``` ```json { "token_type": "Bearer", "expires_in": 3600, "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJS...", "refresh_token": "def50200a5c7..." } ``` -------------------------------- ### List and Delete Clients (CLI) Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt List existing OAuth2 clients with filtering options or delete clients by identifier using the command-line interface. ```APIDOC ## List and Delete Clients (CLI) ### Description List existing OAuth2 clients with filtering options or delete clients by identifier. ### Method CLI Command ### Endpoint `bin/console league:oauth2-server:list-clients` `bin/console league:oauth2-server:delete-client ` ### Parameters #### List Clients (`list-clients`) ##### Query Parameters - **--columns** (string) - Optional - Specifies which columns to display (e.g., "identifier, scope, grant type"). - **--grant-type** (string) - Optional - Filters clients by a specific grant type. - **--scope** (string) - Optional - Filters clients by a specific scope. #### Delete Client (`delete-client`) ##### Path Parameters - **client_id** (string) - Required - The identifier of the client to delete. ### Request Example ```sh # List all clients bin/console league:oauth2-server:list-clients # List with specific columns bin/console league:oauth2-server:list-clients --columns="identifier, scope, grant type" # Filter by grant type and scope bin/console league:oauth2-server:list-clients --grant-type=authorization_code --scope=email # Delete a client bin/console league:oauth2-server:delete-client my_client_id ``` ### Response - **list-clients**: Typically outputs a table of clients matching the criteria. - **delete-client**: No specific response format is detailed for CLI operations, success is typically indicated by the absence of errors. ``` -------------------------------- ### Enable All Scopes with Role Hierarchy Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/token-scopes.md Workaround to grant clients without scopes access to all available scopes by using role hierarchy. Ensure the 'role_prefix' is set appropriately. ```yaml # config/packages/league_oauth2_server.yaml league_oauth2_server: role_prefix: ROLE_OAUTH2_ scopes: available: [EMAIL, PREFERENCES, SUPER_USER] default: [SUPER_USER] ``` ```yaml # config/packages/security.yaml security: role_hierarchy: ROLE_OAUTH2_SUPER_USER: [ROLE_OAUTH2_EMAIL, ROLE_OAUTH2_PREFERENCES] ``` -------------------------------- ### Password Grant - UserResolveEvent Listener Implementation Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt Implement the `UserResolveListener` to authenticate users for the password grant by listening to the `UserResolveEvent`. This listener loads the user, checks their password validity, and sets the user on the event if authentication is successful. ```php userProvider->loadUserByIdentifier($event->getUsername()); } catch (AuthenticationException $e) { return; } if (!$user instanceof PasswordAuthenticatedUserInterface) { return; } if (!$this->passwordHasher->isPasswordValid($user, $event->getPassword())) { return; } $event->setUser($user); } } ``` -------------------------------- ### List and Delete OAuth2 Clients (CLI) Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt List existing OAuth2 clients with filtering options or delete clients by identifier. ```sh bin/console league:oauth2-server:list-clients ``` ```sh bin/console league:oauth2-server:list-clients --columns="identifier, scope, grant type" ``` ```sh bin/console league:oauth2-server:list-clients \ --grant-type=authorization_code \ --scope=email ``` ```sh bin/console league:oauth2-server:delete-client my_client_id ``` -------------------------------- ### Generate OAuth2 Key Pair Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt Generate RSA public/private key pair for token signing using the console command. Options include custom paths, passphrases, and overwriting existing keys. ```sh bin/console league:oauth2-server:generate-key-pair bin/console league:oauth2-server:generate-key-pair \ --dir=%kernel.project_dir%/var/oauth \ --passphrase=your-secret-passphrase bin/console league:oauth2-server:generate-key-pair --overwrite ``` -------------------------------- ### List OAuth2 Clients Command Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/basic-setup.md Use this command to list existing OAuth2 clients. You can filter clients by redirect URI, grant type, or scope, and customize the displayed columns. ```sh Description: Lists existing oAuth2 clients Usage: league:oauth2-server:list-clients [options] Options: --columns=COLUMNS Determine which columns are shown. Comma separated list. [default: "identifier, secret, scope, redirect uri, grant type"] --redirect-uri=REDIRECT-URI Finds by redirect uri for client. Use this option multiple times to filter by multiple redirect URIs. (multiple values allowed) --grant-type=GRANT-TYPE Finds by allowed grant type for client. Use this option multiple times to filter by multiple grant types. (multiple values allowed) --scope=SCOPE Finds by allowed scope for client. Use this option multiple times to find by multiple scopes. (multiple values allowed)__ ``` -------------------------------- ### Configure Custom Client Classname Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/using-custom-client.md Update the bundle configuration to use your custom client class instead of the default `League\Bundle\OAuth2ServerBundle\Model\Client`. This tells the bundle where to find your extended client model. ```yaml league_oauth2_server: client: classname: App\Entity\Client ``` -------------------------------- ### Implement Custom Grant Type Interface Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/implementing-custom-grant-type.md Create a PHP class that implements `League\Bundle\OAuth2ServerBundle\League\AuthorizationServer\GrantTypeInterface`. This class defines the behavior of your custom grant. ```php foo = $foo; } public function getIdentifier() { return 'fake_grant'; } public function respondToAccessTokenRequest(ServerRequestInterface $request, ResponseTypeInterface $responseType, DateInterval $accessTokenTTL) { return new Response(); } public function getAccessTokenTTL(): ?DateInterval { return new DateInterval('PT5H'); } } ``` -------------------------------- ### Configure Low-Level OAuth2 Event Listeners Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt YAML configuration to register the OAuth2EventListener as a Symfony service and tag it as an event listener for the access_token.issued and refresh_token.issued events. ```yaml # config/services.yaml services: App\EventListener\OAuth2EventListener: tags: - { name: kernel.event_listener, event: access_token.issued, method: onAccessTokenIssued } - { name: kernel.event_listener, event: refresh_token.issued, method: onRefreshTokenIssued } ``` -------------------------------- ### Listen to Low-Level OAuth2 Server Events Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt Subscribe to low-level events from the underlying oauth2-server library for logging or custom behavior. Requires a LoggerInterface to be injected. ```php logger->info('Access token issued', [ 'client_id' => $event->getClient()->getIdentifier(), 'user_id' => $event->getAccessToken()->getUserIdentifier(), ]); } public function onRefreshTokenIssued(RequestRefreshTokenEvent $event): void { $this->logger->info('Refresh token issued', [ 'access_token_id' => $event->getRefreshToken()->getAccessToken()->getIdentifier(), ]); } } ``` -------------------------------- ### Request Access Token (Client Credentials Grant) Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt Request access tokens using client credentials grant for machine-to-machine authentication. Requires client ID and secret. ```sh curl -X POST https://example.com/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "client_id=my_client_id" \ -d "client_secret=my_client_secret" \ -d "scope=email profile" ``` ```json { "token_type": "Bearer", "expires_in": 3600, "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJS..." } ``` -------------------------------- ### Define Custom Client Entity Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/using-custom-client.md Create a PHP class that extends `AbstractClient` to define custom properties for your OAuth2 clients. Ensure it includes necessary Doctrine mappings if using an ORM. ```php userProvider = $userProvider; $this->userPasswordHasher = $userPasswordHasher; } public function onUserResolve(UserResolveEvent $event): void { try { $user = $this->userProvider->loadUserByIdentifier($event->getUsername()); } catch (AuthenticationException $e) { return; } if (null === $user || !($user instanceof PasswordAuthenticatedUserInterface)) { return; } if (!$this->userPasswordHasher->isPasswordValid($user, $event->getPassword())) { return; } $event->setUser($user); } } ``` -------------------------------- ### Password Grant - UserResolveEvent Listener Configuration Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt Configure the `UserResolveListener` in `config/services.yaml` to handle user authentication for the password grant. This listener uses the `UserProviderInterface` and `UserPasswordHasherInterface` to validate user credentials. ```yaml # config/services.yaml services: App\EventListener\UserResolveListener: arguments: - '@security.user_providers' - '@security.password_hasher' tags: - { name: kernel.event_listener, event: league.oauth2_server.event.user_resolve, method: onUserResolve } ``` -------------------------------- ### Require OAuth2 Server Bundle Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/README.md Use Composer to add the OAuth2 Server Bundle to your Symfony project. This is the initial step for integration. ```sh composer require league/oauth2-server-bundle ``` -------------------------------- ### Set Default Token Scopes Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/token-scopes.md Configure default scopes in the bundle configuration. These scopes are applied when a client does not request any specific scopes. ```yaml # config/packages/league_oauth2_server.yaml league_oauth2_server: scopes: available: [EMAIL, PREFERENCES] default: [EMAIL] ``` -------------------------------- ### Configure Security Firewall for OAuth2 Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt Configure Symfony security firewalls to protect API routes with OAuth2 authentication while keeping token endpoints public. ```yaml security: enable_authenticator_manager: true firewalls: api_token: pattern: ^/token$ security: false api_device_code: pattern: ^/device-code$ security: false api: pattern: ^/api security: true stateless: true oauth2: true access_control: - { path: ^/authorize, roles: IS_AUTHENTICATED_REMEMBERED } - { path: ^/api, roles: IS_AUTHENTICATED_FULLY } ``` -------------------------------- ### Configure Authorization Request Listener Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt YAML configuration to register the AuthorizationRequestListener as a Symfony service and tag it as an event listener for the authorization_request_resolve event. ```yaml # config/services.yaml services: App\EventListener\AuthorizationRequestListener: tags: - { name: kernel.event_listener, event: league.oauth2_server.event.authorization_request_resolve, method: onAuthorizationRequest } ``` -------------------------------- ### Configure Scope Resolution Listener Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt YAML configuration to register the ScopeResolveListener as a Symfony service and tag it as an event listener for the scope_resolve event. ```yaml # config/services.yaml services: App\EventListener\ScopeResolveListener: tags: - { name: kernel.event_listener, event: league.oauth2_server.event.scope_resolve, method: onScopeResolve } ``` -------------------------------- ### Programmatic Client Management Service Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt Manage OAuth2 clients programmatically using the ClientManagerInterface. This service provides methods to create, revoke, and delete clients. ```php setRedirectUris(...array_map(fn($uri) => new RedirectUri($uri), $redirectUris)); $client->setGrants(...array_map(fn($grant) => new Grant($grant), $grantTypes)); $client->setScopes(...array_map(fn($scope) => new Scope($scope), $scopes)); $client->setActive(true); $this->clientManager->save($client); return $client; } public function revokeClient(string $identifier): void { $client = $this->clientManager->find($identifier); if ($client) { $client->setActive(false); $this->clientManager->save($client); } } public function deleteClient(string $identifier): void { $client = $this->clientManager->find($identifier); if ($client) { $this->clientManager->remove($client); } } } ``` -------------------------------- ### Configure Security Layer Firewalls Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/basic-setup.md Configure Symfony security firewalls to enable the OAuth2 authenticator. Specific firewalls are set up for token/device code endpoints and API routes, with the 'api' firewall requiring a valid access token. ```yaml security: enable_authenticator_manager: true firewalls: api_token: pattern: ^/token$ security: false api_device_code: pattern: ^/device-code$ security: false api: pattern: ^/api security: true stateless: true oauth2: true ``` -------------------------------- ### Update Doctrine Schema Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/index.md Run this command to update your database schema to support the bundle's entities. ```sh bin/console doctrine:schema:update --force ``` -------------------------------- ### Secure Authorization Endpoint Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/index.md Configure access control in `config/security.yaml` to ensure only authenticated users can access the authorization endpoint. ```yaml security: access_control: - { path: ^/authorize, roles: IS_AUTHENTICATED_REMEMBERED } ``` -------------------------------- ### Register an Event Listener in Symfony Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/listening-to-league-events.md Register your custom event listener using Symfony's service configuration. Specify the event name and the method to call on your listener. ```yaml services: App\EventListener\FooListener: tags: - { name: kernel.event_listener, event: access_token.issued, method: onAccessTokenIssuedEvent } ``` -------------------------------- ### Require Doctrine for Persistence Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/README.md If you plan to use Doctrine as the persistence layer for your OAuth2 Server Bundle, you need to require the necessary Doctrine bundles. This sets up the database interaction. ```sh composer require doctrine/doctrine-bundle doctrine/orm ``` -------------------------------- ### Handle Authorization Request Consent Flow Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt Listen to AuthorizationRequestResolveEvent to manage consent flow. Auto-approves trusted first-party clients or redirects third-party clients to a consent page. ```php getUser(); $client = $event->getClient(); $scopes = $event->getScopes(); // Auto-approve for trusted first-party clients if ($client->getIdentifier() === 'trusted_first_party_app') { $event->resolveAuthorization(AuthorizationRequestResolveEvent::AUTHORIZATION_APPROVED); return; } // Redirect to consent page for third-party clients $consentUrl = $this->urlGenerator->generate('oauth_consent', [ 'client_id' => $client->getIdentifier(), 'scopes' => implode(' ', array_map(fn($s) => (string)$s, $scopes)), ]); $event->setResponse(new RedirectResponse($consentUrl)); } } ``` -------------------------------- ### Configure Device Code Verification URI Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/device-code-grant.md Set the device code verification URI in your Symfony configuration. This URL will be provided to the user on their secondary device for authentication. ```yaml league_oauth2_server: authorization_server: device_code_verification_uri: 'https://your-domain.com/verify-device' ``` -------------------------------- ### Handle User Code Input in Symfony Controller Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/device-code-grant.md This controller handles user code input for device authorization. It requires a form to capture the user code and uses the DeviceCodeManager to find the device code. Ensure the authorization server is configured correctly and the user is authenticated. ```php createFormBuilder() ->add('userCode', TextType::class, [ 'required' => true, ]) ->getForm() ->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { try { $deviceCode = $this->deviceCodeManager->findByUserCode($form->get('userCode')->getData()); if (null === $deviceCode) { throw OAuthServerException::invalidGrant('Invalid user code'); } $this->authorizationServer->completeDeviceAuthorizationRequest( $deviceCode->getIdentifier(), $this->getUser()->getId(), true // User has approved the device on his end ); // Device code approved, show success message to user } catch (OAuthServerException $e) { // Handle exception (invalid code or missing user ID) } } // Render the form to the user } ``` -------------------------------- ### Extend AbstractClient for Custom Client Entity Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt Extend the AbstractClient class to add custom properties like image, description, and trusted status to your OAuth2 clients. Ensure your entity is mapped correctly with Doctrine ORM. ```php image; } public function setImage(?string $image): self { $this->image = $image; return $this; } public function getDescription(): ?string { return $this->description; } public function setDescription(?string $description): self { $this->description = $description; return $this; } public function isTrusted(): bool { return $this->trusted; } public function setTrusted(bool $trusted): self { $this->trusted = $trusted; return $this; } } ``` ```yaml # config/packages/league_oauth2_server.yaml league_oauth2_server: client: classname: App\Entity\Client ``` -------------------------------- ### Register Custom Grant Type Service Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/implementing-custom-grant-type.md Register your custom grant type class as a service in your Symfony application's configuration. Ensure it is autoconfigured or tagged with `league.oauth2_server.authorization_server.grant`. ```yaml services: _defaults: autoconfigure: true App\Grant\FakeGrant: ~ ``` -------------------------------- ### Scope Resolve Event Listener Source: https://github.com/thephpleague/oauth2-server-bundle/blob/master/docs/token-scopes.md Implement a listener for the 'league.oauth2_server.event.scope_resolve' event to modify access token scopes. Subscribe to the event in your service configuration. ```php getScopes(); // ...Make adjustments to the client's requested scopes... $event->setScopes(...$requestedScopes); } } ``` ```yaml App\EventListener\ScopeResolveListener: tags: - { name: kernel.event_listener, event: league.oauth2_server.event.scope_resolve, method: onScopeResolve } ``` -------------------------------- ### Request Access Token (Authorization Code Grant) Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt Exchange authorization code for access and refresh tokens after user authorization. Involves redirecting the user and then exchanging the code. ```http # Step 1: Redirect user to authorization endpoint # GET https://example.com/authorize? # response_type=code& # client_id=my_client_id& # redirect_uri=https://myapp.com/callback& # scope=email%20profile& # state=random_state_string& # code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM& # code_challenge_method=S256 ``` ```sh # Step 2: Exchange code for tokens curl -X POST https://example.com/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code" \ -d "client_id=my_client_id" \ -d "client_secret=my_client_secret" \ -d "code=auth_code_from_callback" \ -d "redirect_uri=https://myapp.com/callback" \ -d "code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk" ``` ```json { "token_type": "Bearer", "expires_in": 3600, "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJS...", "refresh_token": "def50200a5c7..." } ``` -------------------------------- ### Request Access Token (Refresh Token Grant) Source: https://context7.com/thephpleague/oauth2-server-bundle/llms.txt Obtain new access tokens using a valid refresh token. This is used to extend the lifespan of an authenticated session. ```sh curl -X POST https://example.com/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=refresh_token" \ -d "client_id=my_client_id" \ -d "client_secret=my_client_secret" \ -d "refresh_token=def50200a5c7..." \ -d "scope=email" ``` ```json { "token_type": "Bearer", "expires_in": 3600, "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJS...", "refresh_token": "def50200b8d9..." } ```