1

How can we configure Symfony 4 Remember me functionality to use email instead of username (as set by default) when creating the cookie and storing it in the browser?

My issue is that by using email to authenticate in S4, the cookie is created with the username instead of the email in its hash, stored in the browser but when S4 check my cookie to see if IS_AUTHENTICATED_REMEMBERED is true, it checks it against the username stored in the DB which doesn’t make sens. It should check it against email. So my remember me functionality doesn’t work. If I use the username to login, then it works, but that’s not what I want, I’d like my users to log in with their email address.

I’ve configurered the login to work with email instead of the default username behavior, but I can’t have remember me working that way.

I tried the following in my security.yaml

security:
    encoders:
        App\Entity\User:
            algorithm: bcrypt
    providers:
        user_provider:
            entity:
                class: App\Entity\User
                property: email
        in_memory: { memory: ~ }
        our_db_provider:
            entity:
                class: App\Entity\User
                property: email
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            pattern:    ^/
            http_basic: ~
            provider: our_db_provider
            anonymous: ~
            form_login:
                login_path: login
                check_path: login
                default_target_path: dashboard
                username_parameter: email
                password_parameter: password
                remember_me: true
            remember_me:
                secret:   '%kernel.secret%'
                lifetime: 31536000 # 1 week in seconds
                path: /
                domain: ~
                secure:   true
                name:     REMEMBERME
                remember_me_parameter: remember_me
                always_remember_me: true
            logout:
                path:  /logout
                target: /

but this doesn’t let you parameter what field remember is using to generate the hash stored in the cookie.

If you’ve managed to set up your login / authentication & remember me working with a field different than username, please share :)

UPDATE: I tried Ahmed answer with the following lines on services but it’s not working:

App\Security\TokenBasedRememberMeServices:
      decorates: Symfony\Component\Security\Http\RememberMe\TokenBasedRememberMeServices

it says You have requested a non-existent service "Symfony\Component\Security\Http\RememberMe\TokenBasedRememberMeServices”.

Miles M.
  • 4,089
  • 12
  • 62
  • 108
  • You decoded the hash to test and you found tha's a username inside ? – famas23 Jan 06 '19 at 23:15
  • Haha, If I would have decoded the hash I’l would have cracked sha256! Probably would be hacking Bictoin right now ^^ I looked at what the symfony log in the profiler was telling me. And it was saying something like couldn’t find the user “My_username” . It should be looking for an email and not a username – Miles M. Jan 06 '19 at 23:22
  • 1
    I'm not sure I think the problem that security component use `getUsername()` getter to build the token take a look https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php#L74 anyway i searched a bit and i found a soluition, maybe it can help you https://stackoverflow.com/questions/19505555/symfony2-remember-me-tries-to-authenticate-by-username-instad-of-email and if you want to override an existant service you need to work with decorates it think https://symfony.com/doc/current/service_container/service_decoration.html – famas23 Jan 06 '19 at 23:31
  • thanks Ahmed this is very valuable. I will try – Miles M. Jan 06 '19 at 23:39
  • 1
    If this worked let me know i will propose you a clear solution – famas23 Jan 06 '19 at 23:55
  • Yeah that’s definitively the right way to go, therefore you should go ahead and write an answer. I’m just unsure of what my services.yaml should look like and where to put my new created class that extends `TokenBasedRememberMeServices` – Miles M. Jan 07 '19 at 00:00
  • So I actually tried to implement this, but it seems my decoration definition can't be correct as the code run is still the one in TokenBasedRememberMeServices... Any hint? – Schyzophrenic Jun 17 '21 at 10:39

2 Answers2

1

The problem that security component use getUsername() getter to build the token https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php#L74

So we need to overide the service responosible for creating the remember-me cookie, wish is security.authentication.rememberme.services.simplehash.class.

Firstable: Update the onLoginSuccess method L74 so it uses the email instead of the username.

namespace App\Security;
...
class TokenBasedRememberMeServices extends AbstractRememberMeServices
{
    ....
    protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token)
    {
      ...
        $value = $this->generateCookieValue(\get_class($user), $user->getEmail(), $expires, $user->getPassword());
      ...
    }
...

Second: Register your class as a service.

 App\Security\TokenBasedRememberMeServices:
     decorates: 'security.authentication.rememberme.services.simplehash.class'

Or you can flow the contract under UserInterface It define and returns the username used to authenticate the user. In our case it's the email property.

public function getUsername()
{
    return $this->email;
}
famas23
  • 2,072
  • 4
  • 17
  • 53
1

I don't have enough SO reputation to add a comment for answer upon, so I write it here.

Instead of decorating service:

security.authentication.rememberme.services.simplehash.class

Decorate:

security.authentication.rememberme.services.simplehash

It works on Symfony 4.4

Yan Sklyarenko
  • 31,557
  • 24
  • 104
  • 139
Bosswell
  • 11
  • 1