## OAuth2 authorization server used for API/MCP app auto-provisioning (see docs/api/authentication.md). # # Uses the bundle's own Doctrine persistence (its Client/AccessToken/RefreshToken/AuthorizationCode # entities, tables prefixed "oauth2_") rather than custom entities/repositories, so upstream bundle # upgrades keep this working without us having to touch repository code every time (as happened going # from league/oauth2-server 8.5 to 9.2). OAuth-issued tokens are therefore a distinct credential type # from App\Entity\UserSystem\ApiToken (Personal Access Tokens) - see App\Security\OAuth\OAuthBearerAuthenticator # for how incoming requests are routed to the right validator, and role_prefix below for how OAuth scopes # end up granting the exact same ROLE_API_* roles the existing permission system (config/permissions.yaml) # already understands. league_oauth2_server: authorization_server: private_key: '%kernel.project_dir%/var/oauth2/private.key' private_key_passphrase: null encryption_key: '%env(OAUTH2_ENCRYPTION_KEY)%' encryption_key_type: 'defuse' access_token_ttl: 'PT1H' refresh_token_ttl: 'P30D' auth_code_ttl: 'PT10M' # Only Authorization Code (+ PKCE) and Refresh Token are supported - no client secrets, no # password grant, no implicit grant, no device code. enable_client_credentials_grant: false enable_password_grant: false enable_implicit_grant: false enable_device_code_grant: false enable_auth_code_grant: true enable_refresh_token_grant: true require_code_challenge_for_public_clients: true revoke_refresh_tokens: true # No response_type_class override: access tokens are real JWTs (the bundle's default). Clients # only ever treat access_token as an opaque string per the OAuth2 spec, so this is not a # compatibility concern - and it means the RSA keypair below is actually used, unlike the earlier # custom-repository design. resource_server: public_key: '%kernel.project_dir%/var/oauth2/public.key' scopes: # Scopes map 1:1 onto the existing App\Entity\UserSystem\ApiTokenLevel enum names. Combined with # role_prefix below, an OAuth token scoped "edit" ends up with role ROLE_API_EDIT - the exact same # role App\Entity\UserSystem\ApiTokenLevel::EDIT grants a Personal Access Token, so # config/permissions.yaml's apiTokenRole mappings apply unchanged to both credential types (see # App\Services\UserSystem\VoterHelper for the permission-ceiling check both types go through). available: ['read_only', 'edit', 'admin', 'full'] default: ['read_only'] persistence: doctrine: table_prefix: 'oauth2_' client: allow_plaintext_secrets: false # Roles end up as ROLE_API_, e.g. ROLE_API_READ_ONLY - see the "scopes" comment above. role_prefix: 'ROLE_API_'