Skip to content

Development security

Tip

See Permissions for information about the permissions system in Ibexa DXP.

Security checklist

See the Security checklist for a list of security-related issues you should take care of before going live with a project.

Symfony authentication

To use Symfony authentication with Ibexa DXP, use the following configuration (in config/packages/security.yaml):

1
2
3
4
5
6
7
8
9
security:
    firewalls:
        ibexa_front:
            pattern: ^/
            user_checker: Ibexa\Core\MVC\Symfony\Security\UserChecker
            anonymous: ~
            form_login:
                require_previous_session: false
            logout: ~

And in config/routes.yaml:

1
2
3
4
5
6
7
login:
    path: /login
    defaults: { _controller: Ibexa\Core\MVC\Symfony\Controller\SecurityController::loginAction }
login_check:
    path: /login_check
logout:
    path: /logout

Note

You can fully customize the routes and/or the controller used for login. However, remember to match login_path, check_path and logout.path from security.yaml.

See security configuration reference and standard login form documentation.

Authentication using Symfony Security component

Authentication is provided by the Symfony Security component.

Native and universal form_login is used, in conjunction with an extended DaoAuthenticationProvider (DAO stands for Data Access Object), the RepositoryAuthenticationProvider. Native behavior of DaoAuthenticationProvider has been preserved, making it possible to still use it for pure Symfony applications.

Security controller

A SecurityController is used to manage all security-related actions and is thus used to display the login form. It follows all standards explained in Symfony security documentation.

The base template used is Security/login.html.twig.

The layout used by default is %ibexa.content_view.viewbase_layout% (empty layout) but can be configured together with the login template:

1
2
3
4
5
6
ibexa:
    system:
        my_siteaccess:
            user:
                layout: layout.html.twig
                login_template: user/login.html.twig
Redirection after login

By default, Symfony redirects to the URI configured in security.yaml as default_target_path. If not set, it defaults to /.

Remember me

It's possible to use the "Remember me" functionality. Refer to the Symfony cookbook on this topic.

If you want to use this feature, you must at least extend the login template to add the required checkbox:

1
2
3
4
5
6
7
{% extends "@IbexaCore/Security/login.html.twig" %}

{% block login_fields %}
    {{ parent() }}
    <input type="checkbox" id="remember_me" name="_remember_me" checked />
    <label for="remember_me">Keep me logged in</label>
{% endblock %}

Login handlers / SSO

Symfony provides native support for multiple user providers. This makes it easy to integrate any kind of login handlers, including SSO and existing third-party bundles (for example, FR3DLdapBundle, HWIOauthBundle, FOSUserBundle, BeSimpleSsoAuthBundle, and more).

See Authenticating a user with multiple user provider for more information.

JWT authentication

To use JWT authentication with Ibexa DXP, in the provided config/packages/lexik_jwt_authentication.yaml file, modify the existing configuration by setting authorization_header to enabled:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
lexik_jwt_authentication:
    secret_key: '%env(APP_SECRET)%'
    encoder:
        signature_algorithm: HS256
    # Disabled by default, because Page builder uses a custom extractor
    token_extractors:
        authorization_header:
            enabled: true
        cookie:
            enabled: false
        query_parameter:
            enabled: false

You also need to configure Symfony firewalls for the APIs with which you want to use JWT authentication. It's already provided in config/packages/security.yaml, you need to uncomment the ibexa_jwt_rest and the ones for the desired APIs:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
security:
    firewalls:
        ibexa_jwt_rest:
            request_matcher: Ibexa\Rest\Security\JWTTokenCreationRESTRequestMatcher
            user_checker: Ibexa\Core\MVC\Symfony\Security\UserChecker
            stateless: true
            provider: ibexa
            json_login:
                check_path: ibexa.rest.create_token
                username_path: JWTInput.username
                password_path: JWTInput.password
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure

        ibexa_jwt_rest.api:
            request_matcher: Ibexa\Rest\Security\AuthorizationHeaderRESTRequestMatcher
            user_checker: Ibexa\Core\MVC\Symfony\Security\UserChecker
            provider: ibexa
            stateless: true
            jwt: ~

        ibexa_jwt_mcp:
            request_matcher: Ibexa\Mcp\Security\McpRequestMatcher
            user_checker: Ibexa\Core\MVC\Symfony\Security\UserChecker
            provider: ibexa
            stateless: true
            jwt: ~

        ibexa_jwt_graphql:
            request_matcher: Ibexa\GraphQL\Security\NonAdminGraphQLRequestMatcher
            provider: ibexa
            stateless: true
            jwt: ~

For example, to use JWT authentication only for MCP servers and keep session-based authentication for REST and GraphQL:

  • uncomment ibexa_jwt_rest and ibexa_jwt_mcp to activate them
  • keep ibexa_jwt_rest.api and ibexa_jwt_graphql commented and disabled

Use PEM keys

Out of the box, JWT tokens are created using Hash-based Message Authentication Code (HMAC) with APP_SECRET as the secret key and the HMAC-SHA256 (HS256) algorithm.

You can use Privacy-enhanced Electronic Mail (PEM) keys and the RSA-SHA256 (RS256) algorithm instead.

  1. Set JWT_PASSPHRASE secret

In a .env file, you should have the following variables:

1
2
3
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ……

Set your JWT_PASSPHRASE, its value needs to be a strong, random, and securely stored value. For more recommendations and how to generate one, see APP_SECRET and other secret.

  1. In config/packages/lexik_jwt_authentication.yaml, use the following configuration:
1
2
3
4
5
6
7
lexik_jwt_authentication:
    secret_key: '%env(resolve:JWT_SECRET_KEY)%'
    public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
    pass_phrase: '%env(JWT_PASSPHRASE)%'
    encoder:
        signature_algorithm: RS256
    # …
  1. Generate a PEM encoded key pair in config/jwt directory by using the command:
1
php bin/console lexik:jwt:generate-keypair

Ibexa Cloud

To store the tokens on Ibexa Cloud, define the config/jwt directory as a volume in the .platform.app.yaml file. In 3-node cluster setups, ensure that the key pair is the same on all 3 servers. You can use a network share, or use a local mount and manually copy the key pair between the servers.

For more information, see LexikJWTAuthenticationBundle configuration reference.