2026-07-26 19:51:10 +02:00
|
|
|
## OAuth2 authorization server used for API/MCP app auto-provisioning (see docs/api/authentication.md).
|
|
|
|
|
#
|
2026-07-26 20:29:58 +02:00
|
|
|
# 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.
|
2026-07-26 19:51:10 +02:00
|
|
|
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
|
2026-07-26 20:29:58 +02:00
|
|
|
# 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.
|
2026-07-26 19:51:10 +02:00
|
|
|
resource_server:
|
|
|
|
|
public_key: '%kernel.project_dir%/var/oauth2/public.key'
|
|
|
|
|
scopes:
|
2026-07-26 20:29:58 +02:00
|
|
|
# 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).
|
2026-07-26 19:51:10 +02:00
|
|
|
available: ['read_only', 'edit', 'admin', 'full']
|
|
|
|
|
default: ['read_only']
|
|
|
|
|
persistence:
|
2026-07-26 20:29:58 +02:00
|
|
|
doctrine:
|
|
|
|
|
table_prefix: 'oauth2_'
|
2026-07-26 19:51:10 +02:00
|
|
|
client:
|
|
|
|
|
allow_plaintext_secrets: false
|
2026-07-26 20:29:58 +02:00
|
|
|
# Roles end up as ROLE_API_<SCOPE>, e.g. ROLE_API_READ_ONLY - see the "scopes" comment above.
|
|
|
|
|
role_prefix: 'ROLE_API_'
|