I am working on a legacy symfony project and I want to integrate jwt token authentication for my rest section and maybe for a full migration later, but I am facing an issue. I defined my both firewalls in security.yaml and each of them are working fine when the other one is deactivated, but when I configure them both in the file, the first one defined in the file is taking over the authentication and the second one doesn't whatever authentication type it is.
Here's what I've done in the file so far:
security:
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
App\Entity\User:
algorithm: auto
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
json_login:
check_path: app_login
username_path: email
password_path: password
success_handler: AuthenticationSuccessHandler
logout:
path: app_logout
two_factor:
prepare_on_login: true
prepare_on_access_denied: true
authentication_required_handler: TwoFactorAuthenticationRequiredHandler
success_handler: TwoFactorAuthenticationSuccessHandler
failure_handler: TwoFactorAuthenticationFailureHandler
auth_form_path: 2fa_login # The route name you have used in the routes.yaml
check_path: 2fa_login_check # The route name you have used in the routes.yaml
enable_csrf: true
restlogin:
stateless: true
pattern: ^/rest/login
json_login:
check_path: login_check
username_path: email
password_path: password
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
# custom_authenticator: App\Security\RestLoginAuthenticator
rest:
pattern: ^/rest
stateless: true
jwt: ~
restsignup:
pattern: ^/rest/signup
stateless: true
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#the-firewall
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# The path patterns shown here have to be updated according to your routes.
# IMPORTANT: ADD THESE ACCESS CONTROL RULES AT THE VERY TOP OF THE LIST!
access_control:
# REST
- { path: ^/rest/login, roles: PUBLIC_ACCESS }
# - { path: ^/rest, roles: IS_AUTHENTICATED_FULLY }
# This makes the logout route accessible during two-factor authentication. Allows the user to
# cancel two-factor authentication, if they need to.
- { path: ^/, role: PUBLIC_ACCESS }
- { path: ^/logout, role: PUBLIC_ACCESS }
# This ensures that the form can only be accessed when two-factor authentication is in progress.
- { path: ^/2fa, role: IS_AUTHENTICATED_2FA_IN_PROGRESS }
# - { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
Note: everything but restlogin, rest and restsignup is legacy code and I don't want to break anything already running.
And the routes structure is like this:
| /
| login
| register
| logout
| other legacy routes
| rest/
| login
| signup
| logout
| other api routes
I thought the easiest way to solve this would be to tell the main firewall to ignore everything under the rest route and let the rest firewalls to handle this but I still get 401 errors when calling /rest/login despite the fact that I have set a public access in the access_control section. Please note that kind of the same behavior occurs as well when restlogin is placed above main in the file, the effect being that the getUser() function always returns null in the controller.
After many attempts I cannot figure out what I'm doing wrong in the configuration and didn't hear anywhere that symfony cannot support different authentication types in the same app.
Context: I am using lexik jwt authentication bundle 2.19 and symfony 6.2.
Does someone have any successfull experience using symfony built-in authentication and lexik jwt at the same time?
Solved by redefining the firewalls.