The CWA is in heavy development
The CWA is still in alpha and not ready for production - some code and implementations are likely to change. If you would like to try out the CWA, please enjoy what we have provided and feel free to provide feedback, or get involved on GitHub.
DraftApi

Configuration Reference

Complete reference for all silverback_api_components bundle configuration options.

Full YAML structure with every option, its type, and default value. The minimum required fields are website_name, user.class_name, and refresh_token.*.

Full Configuration

silverback_api_components:

    # Required. Used in email subjects and templates.
    website_name: My CWA App

    # Table prefix for all bundle-managed tables. Default: '_acb_'
    table_prefix: '_acb_'

    # Key under which runtime metadata is nested in API responses. Default: '_metadata'
    metadata_key: '_metadata'

    # ─── User ────────────────────────────────────────────────────────────────
    user:
        # Required. Fully-qualified class name of your User entity.
        class_name: App\Entity\User

        email_verification:
            enabled: true
            # Whether new users start verified (false = must verify email)
            default_value: false
            # Send a verification email when a new user registers
            verify_on_register: true
            # Re-send verification when the user changes their email
            verify_on_change: true
            # Block login for unverified email addresses
            deny_unverified_login: true
            email:
                # Query param name carrying the redirect path (optional)
                redirect_path_query: ~
                # Path with {{ username }} and {{ token }} placeholders
                default_redirect_path: /verify-email/{{ username }}/{{ token }}
                subject: Please verify your email

        new_email_confirmation:
            email:
                redirect_path_query: ~
                default_redirect_path: /confirm-new-email/{{ username }}/{{ new_email }}/{{ token }}
                subject: Please confirm your new email address
            # Token validity in seconds. Default: 86400 (24 hours)
            request_timeout_seconds: 86400

        password_reset:
            email:
                redirect_path_query: ~
                default_redirect_path: /reset-password/{{ username }}/{{ token }}
                subject: Your password reset request
            # Minimum seconds between reset requests. Default: 8600
            repeat_ttl_seconds: 8600
            # Reset token validity in seconds. Default: 3600
            request_timeout_seconds: 3600

        emails:
            welcome:
                enabled: true
                subject: 'Welcome to {{ website_name }}'
            user_enabled:
                enabled: true
                subject: 'Your account has been enabled'
            username_changed:
                enabled: true
                subject: 'Your username has been updated'
            password_changed:
                enabled: true
                subject: 'Your password has been changed'

    # ─── Publishable ─────────────────────────────────────────────────────────
    publishable:
        # Symfony expression: who can read/write draft resources and publish
        permission: "is_granted('ROLE_ADMIN')"

    # ─── Built-in Components ─────────────────────────────────────────────────
    enabled_components:
        form: true        # The Form component (Symfony FormType → JSON)
        collection: true  # The Collection component (resource list proxy)

    # ─── Refresh Tokens ──────────────────────────────────────────────────────
    refresh_token:
        # Service ID of the refresh token storage handler
        handler_id: silverback.api_components.refresh_token.storage.doctrine
        options:
            # Your RefreshToken entity class (from the Flex recipe)
            class: App\Entity\RefreshToken
        # Must match the cookie name in lexik_jwt_authentication.set_cookies
        cookie_name: api_components
        # Token lifetime in seconds. Default: 604800 (1 week)
        ttl: 604800
        # The user provider alias used in security.yaml
        database_user_provider: database

    # ─── Mercure ─────────────────────────────────────────────────────────────
    mercure:
        # Name of the Mercure hub (if multiple hubs; null = default hub)
        hub_name: ~
        cookie:
            # SameSite attribute for the Mercure cookie. Default: 'strict'
            samesite: '%env(JWT_COOKIE_SAMESITE)%'
        # Scope subscriber JWT tokens to resources the current user can access.
        # Recommended in production. Default: false (all topics subscribed).
        secure_subscriptions: false

    # ─── Route Security ──────────────────────────────────────────────────────
    # URL pattern → Symfony security expression. Evaluated per-route.
    route_security:
        - { route: '/user-area*', security: "is_granted('ROLE_USER')" }
        - { route: '/admin*', security: "is_granted('ROLE_ADMIN')" }

    # Expression controlling who can access the route manifest
    routable_security: "is_granted('ROLE_ADMIN')"

Mercure Secure Subscriptions

By default the subscriber JWT token issued at login includes every resource topic — Mercure will push updates for any resource the front-end subscribes to, regardless of the current user's access level. This is fine for public content but leaks real-time updates for resources that have server-side security expressions.

Set mercure.secure_subscriptions: true to scope the token: the bundle evaluates each API resource's security expression at token-generation time and omits topics the current user cannot access:

silverback_api_components:
    mercure:
        secure_subscriptions: true

Caveats:

  • Security expressions that reference object (item-level security, e.g. object.owner == user) cannot be evaluated at token time because there is no concrete entity instance. Those resource topics are always included — you cannot scope to specific items, only to the class/role level.
  • The token is generated at login time. If a user's roles change mid-session their subscription scope does not update until they re-authenticate.

Enable in production for any application with role-gated resources. Leave false (the default) for fully public sites.

Environment Variables

VariablePurpose
DATABASE_URLDoctrine connection string
JWT_SECRET_KEYPath to private key PEM file
JWT_PUBLIC_KEYPath to public key PEM file
JWT_PASSPHRASEPrivate key passphrase (.env.local only)
JWT_COOKIE_SAMESITECookie SameSite attribute (strict, lax, none)
MERCURE_URLInternal API → Mercure hub URL
MERCURE_PUBLIC_URLBrowser → Mercure hub URL
MERCURE_JWT_SECRETShared secret for Mercure publisher JWT
MAILER_DSNSymfony Mailer transport
APP_SECRETSymfony application secret

Services You Can Override

All ~320 bundle services have stable string IDs in the form silverback.api_components.*. Each service's FQCN is also registered as an alias, so you can decorate using either form in config/services.yaml:

# config/services.yaml
services:
    App\YourCustomFilesystemProvider:
        decorates: Silverback\ApiComponentsBundle\Helper\Uploadable\FilesystemProvider

    # or equivalently using the stable string ID:
    App\YourCustomFilesystemProvider:
        decorates: silverback.api_components.helper.uploadable.filesystem_provider

Commonly overridden services:

Service IDPurpose
Silverback\ApiComponentsBundle\Helper\Uploadable\FilesystemProviderCustom storage adapter resolution
Silverback\ApiComponentsBundle\Security\UserCheckerCustom account checks on login
silverback.api_components.jwt.authentication.success_handlerPost-login redirect behaviour
silverback.api_components.jwt.authentication.failure_handlerLogin failure response

The string IDs follow the class namespace: Silverback\ApiComponentsBundle\Foo\BarBazsilverback.api_components.foo.bar_baz. Inspect vendor/silverbackdan/api-components-bundle/src/Resources/config/services.php for the full list.