Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Symfony 5 Security: Authenticators

4:41:51

What you'll be learning

This tutorial also works great for Symfony 6!
// composer.json
{
    "require": {
        "php": ">=8.1",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "babdev/pagerfanta-bundle": "^3.3", // v3.3.0
        "composer/package-versions-deprecated": "^1.11", // 1.11.99.4
        "doctrine/annotations": "^1.0", // 1.13.2
        "doctrine/doctrine-bundle": "^2.1", // 2.6.3
        "doctrine/doctrine-migrations-bundle": "^3.0", // 3.1.1
        "doctrine/orm": "^2.7", // 2.10.1
        "knplabs/knp-markdown-bundle": "^1.8", // 1.9.0
        "knplabs/knp-time-bundle": "^1.11", // v1.16.1
        "pagerfanta/doctrine-orm-adapter": "^3.3", // v3.3.0
        "pagerfanta/twig": "^3.3", // v3.3.0
        "phpdocumentor/reflection-docblock": "^5.2", // 5.2.2
        "scheb/2fa-bundle": "^5.12", // v5.12.1
        "scheb/2fa-qr-code": "^5.12", // v5.12.1
        "scheb/2fa-totp": "^5.12", // v5.12.1
        "sensio/framework-extra-bundle": "^6.0", // v6.2.0
        "stof/doctrine-extensions-bundle": "^1.4", // v1.6.0
        "symfony/asset": "5.3.*", // v5.3.4
        "symfony/console": "5.3.*", // v5.3.7
        "symfony/dotenv": "5.3.*", // v5.3.8
        "symfony/flex": "^1.3.1", // v1.17.5
        "symfony/form": "5.3.*", // v5.3.8
        "symfony/framework-bundle": "5.3.*", // v5.3.8
        "symfony/monolog-bundle": "^3.0", // v3.7.0
        "symfony/property-access": "5.3.*", // v5.3.8
        "symfony/property-info": "5.3.*", // v5.3.8
        "symfony/rate-limiter": "5.3.*", // v5.3.4
        "symfony/runtime": "5.3.*", // v5.3.4
        "symfony/security-bundle": "5.3.*", // v5.3.8
        "symfony/serializer": "5.3.*", // v5.3.8
        "symfony/stopwatch": "5.3.*", // v5.3.4
        "symfony/twig-bundle": "5.3.*", // v5.3.4
        "symfony/ux-chartjs": "^1.3", // v1.3.0
        "symfony/validator": "5.3.*", // v5.3.8
        "symfony/webpack-encore-bundle": "^1.7", // v1.12.0
        "symfony/yaml": "5.3.*", // v5.3.6
        "symfonycasts/verify-email-bundle": "^1.5", // v1.5.0
        "twig/extra-bundle": "^2.12|^3.0", // v3.3.3
        "twig/string-extra": "^3.3", // v3.3.3
        "twig/twig": "^2.12|^3.0" // v3.3.3
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.3", // 3.4.0
        "symfony/debug-bundle": "5.3.*", // v5.3.4
        "symfony/maker-bundle": "^1.15", // v1.34.0
        "symfony/var-dumper": "5.3.*", // v5.3.8
        "symfony/web-profiler-bundle": "5.3.*", // v5.3.8
        "zenstruck/foundry": "^1.1" // v1.13.3
    }
}

It's security time! Symfony 5.3 comes with a reimagined version of its security system and I ❤️it! Yes, it's still super flexible & dependable. But the "guts" have been streamlined and simplified, making it easier to get your job done and giving you readable code if you need to dive into the core.

In this course, we'll go from an introduction into Symfony security into a full-blown application with users, permissions, custom voters and multiple ways to authenticate:

  • Generating your User class with make:user
  • Security & Firewall Fundamentals
  • Creating a custom login form with an authenticator
  • Passport object & Badges
  • CSRF protection
  • API token authentication system
  • User Providers (why you need them, but don't care)
  • Password Hashing
  • Logging out!
  • Protecting entire URLs with access_control(s)
  • IS_AUTHENTICATED_FULLY, IS_AUTHENTICATED_REMEMBERED, PUBLIC_ACCESS
  • Checking access with roles! ROLE_USER
  • Denying access in a controller
  • Voters & Complex Permissions
  • Role hierarchies
  • Impersonation (switch_user)
  • Login throttling
  • Automatic Login (after Registration)
  • Hooking into security with events!
  • Two Factor Auth (2FA)!

So let's make:user & make:auth our way to... make:profit... or at least to a great security system!


Your Guides

Ryan Weaver

Buy Access
Login or register to track your progress!

Join the Conversation?

50
Login or Register to join the conversation

Maybe You can cover google recaptcha v3?

1 Reply

Hey Sasa,

Thank you for your interest in SymfonyCasts tutorials!

Yeah, that's a good idea! And probably this course will fit this topic well. I'll add this to our topics list about Security in order to cover it in this tutorial, tough I'm not 100% sure if it will be included or no, but we will try our best.

Thanks for this idea! And if you could tell us a bit more what exactly is complex for you in this topic, or where exactly you're stuck, or what isn't covered by the official docs - that would be awesome and helps us to consider if it should be included in this tutorial or maybe deserves its own mini tutorial.

Cheers!

Reply

Hi Victor,

Thank you for interesting,

I create my security by watching videos from Symfony cast. And now I have problem to implement server side receptcha. There is some bundles but they use symfony forms for rendering login form, and they use Recaptcha3Type as a custom form type field, but I have basic HTML form, and I am confused. Also I founded bundle https://github.com/google/r..., but I don't know where and how to implement server side code.

Also maybe You can consider to cover integration with Oauth2, I find some instruction for implementing: https://dev.to/_mertsimsek/... - but it is much better when You explains it 😊.

Dont get me wrong, I understand that the goal is to present the possibilities of a security bundle, but for someone who does not have a lot of experience, or just want to make something quick and small in Symfony, everything get litle complicated and it takes too much time.

I think that there should be some simple, fast and reusable solution that will cover everything that is needed for authentication (Registration with email validation, reset pass, Log in, Oauth2, receptcha....)

Also I must say that I am very happy that I am accidentally found reset-password-bundle, and verify-email-bundle, and I think that's the right way to simplify and speed things up for Authentication

Best regard

Reply

Hey Sasa!

Thank you for providing more info from your side! It's really helpful when things come to planning a new course :) I won't promise everything your mentioned will be covered in this course, but I'll do my best to deliver this to the course authors, and probably they will fit some topics into it.

Also, good catch on those reset-password-bundle and verify-email-bundle :) Yeah, we would also like to cover them in our future screencasts, those bundles kinda new, and it would help to reveal them to more devs this way.

About oauth, you could also check another our bundle: https://github.com/knpunive... that helps with integration - it also has docs with examples how to configure it in your project.

I hope this helps!

Cheers!

Reply
It O. Avatar

Hi guys, as always i want to know release date.... 😬

1 Reply

Hey It O.!

This is the *next* tutorial - so it's right after Turbo. My guess would be about 3 weeks - it won't be significantly delayed because it's definitely happening after Turbo (I'm mostly not sure because I don't know yet exactly how long Turbo will go).

So, soon! Cjeers!

Reply
Fouad B. Avatar

Awesome, can't wait to transform the current security system.

Reply
It O. Avatar

Thank's Ryan 👍

Reply
Johann Avatar

Hello,
can i use symfonycasts/verify-email-bundle with Symfony 6.3?
I installed it in a 6.3 project, but files that were generated are quite different to the files here in this tutorial or github or in the symfony documentation.
i can't find where the verify URL is generated and no email is send.
maybe there is another bundle for registration confirmation?
thank you for your help.
JD

Reply

Hey @Johann!

Sorry for the slow reply! Yes, it should work just fine, hmm.

but files that were generated are quite different to the files here in this tutorial or github or in the symfony documentation

This is something we will need to check into - I totally see what you're referring to though!

i can't find where the verify URL is generated and no email is send.

When I followed the docs just now, I end up with some code that looks like this:

A) RegistrationController::register() - inside the if ($form->isSubmitted() && $form->isValid()) {, I have:

$this->emailVerifier->sendEmailConfirmation('app_verify_email', $user,
    (new TemplatedEmail())
        ->from(new Address('mailer@example.com', 'AcmeMailBot'))
        ->to($user->getEmail())
        ->subject('Please Confirm your Email')
        ->htmlTemplate('registration/confirmation_email.html.twig')
);

B) In src/Security/EmailVerifier.php, we generate a new helper class to actually send the confirmation email. Its sendEmailConfirmation() contains the code that creates the signedUrl and other variables for confirmation + actually sends the email with $this->mailer->send().

Do you see similar code? Does this help point in the right direction? Emails are always tricky because it's possible everything works... but then a misconfiguration in the email system causes the email to not actually be delivered. However, you can always go to /_profiler and find the POST request to /register and click to see the profiler for that page. There, should be able to click the Emails tab on the left. If an email was sent during the successful registration form submit, you should see it here.

Let me know if that helps!

Cheers!

Reply
Johann Avatar

Hi Ryan,
thanks for the hints. Everything was my bad :-(
for whatever reason i have no debug-toolbar on the 'lost pw request-page'. (i have to investigate this). so i couldn't see the qeued emails because of the forgotten (i forgot) 'Symfony\Component\Mailer\Messenger\SendEmailMessage: async' config. i commented it out, and everything works fine!
thank you

Reply

Woo! I'm just happy it worked! And anyway, this poked me to update the verify bundle docs :)

Cheers!

Reply
mofogasy Avatar
mofogasy Avatar mofogasy | posted 1 year ago | edited

Hello, the database configuration is a pain.

with xampp, when I make:migration I get

` Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB serve

r version for the right syntax to use near 'INDEX idx_9474526c1e27f6bf TO IDX_DADD4A251E27F6BF' at line 1`

then I retry make:migation and I get: Column already exists: 1060 Duplicate column name 'status'

what's going on here ?

Reply

Hey Grenouille,

We're using MySQL server in this course but looks like you have MariaDB installed. Though MySQL and MariaDB almost identical, they may have some differences, and looks like one of it you revealed with that error I'd recommend you to use MySQL instead if you have it installed, otherwise, since it's a learning project and does not contain any important data - you can skip migrations and just run:

$ bin/console doctrine:schema:update --force

It will sync the DB schema with your mapping configuration. You may lose some important data in the DB this way, but if those data are dummy data and you don't care about it - that's totally OK. And you can always reload fixtures again if needed.

I hope this helps!

P.S. But if you you'r working on a real project and will try to deploy changes to production - it seems like you need to regenerate migrations for your specific DB version.

Cheers!

Reply
Default user avatar
Default user avatar GianlucaF | posted 1 year ago | edited

Hi,
is there a way to use CustomCredential with hashed password? I thought this could work but apparently, it doesn't:

`
....
new CustomCredentials(function($credentials, User $user) {

            return $this->passwordHasher->hashPassword($user, $credentials) === $user->getPassword();
        }, $password)`

I'm hashing the given plain password and I'm trying to check the hash using the password hasher.
But it does not work. What is wrong? ( I know I should use PasswordCredential ... )

Reply

Yes, only one chapter to go! 🎉🎉🎉 And off course looking forward for new courses! Is there a place on this site where we can follow which courses are being released in the near future? I know the next one will be EasyAdmin. But i'm really curious for the other *top secret* plans that you have.

Reply

Hey Lex,

Yeah, it's super closed to be released in full already :) Yeah, we do have such a page! Take a look at this link: https://symfonycasts.com/co... - this will list upcoming tutorials, but nothing much there yet except the EastAdmin that you're right should be next, and it should happen very soon already ;)

Thank you for your patience!

Cheers!

Reply
Evgeny Avatar

What about Cache? I can't see any course about Symfony Cache.

Reply

Hey @Solvex

You're right we do not have a dedicated course on cache, but it's because it's just a small thing that we explain in other tutorials. I'll leave you here a chapter that you can watch about caching stuff
https://symfonycasts.com/sc...

Cheers!

Reply
Evgeny Avatar

I don't think cache is simple. Contracts, PSR-6, Marshalling, CachePoolItem, TagAware... In fact, it is very difficult to use, especially the tagged cache. Perhaps a small course of 5-10 lessons will fill in the gaps when using the cache.

Reply

That's a pretty good idea... :)

1 Reply
Evgeny Avatar
Evgeny Avatar Evgeny | posted 1 year ago | edited

@there Hello! Will the course be completed at all?

Reply

Hey Solvex,

Sure! SymfonyCasts doesn't have any courses that were not finished after they had started releasing ;) It will be continued after Christmas / New Year holidays, sorry for any inconvenience and thanks for your patience!

Cheers!

Reply
Evgeny Avatar

Thanks!
We have been looking forward to this course for so long!
Merry Christmas and a Happy New Year!

Reply

Hey Solvex,

Merry Christmas and a Happy New Year to you too! :) Sorry for holiday delays!

Cheers!

Reply
Evgeny Avatar

Спасибо!
Очень эти праздники не вовремя.

Reply
RM Avatar

Hello SymfonyCasts team!
Great job you are doing - i like you tutorials.
Could you please add logout after timeout (logout unactive user) capability to this tutorial?

Reply

Hey @Andris!

Thank you for the nice words :)

> Could you please add logout after timeout (logout unactive user) capability to this tutorial?

That simplest way to implement this is with a session timeout: https://symfony.com/doc/cur...

However, another approach would be to set a "lastActiveTime" property on your User object. I would do that by adding a listener to the RequestEvent (previously called kernel.request): it runs at the start of every request. In there, I would check the logged-in-user's "lastActiveTime" against the current time. If it is too long, then invalidate the session. If it is NOT too long, then update lastActiveTime to the current time.

If you have any questions on this, let me know :). I probably won't talk about it in the tutorial, but I'd be happy to answer questions here.

Cheers!

Reply
RM Avatar

weaverryan
Thank you for reply!
I will do it like you suggest.
Thanks for the solution.

Reply
Gustavo D. Avatar
Gustavo D. Avatar Gustavo D. | posted 1 year ago

When this will be released?

Reply

Hey Gustavo D.

There is not an oficial release date yet but this course should happen after "Doctrine Relations" (https://symfonycasts.com/sc... so, it should not take too long :)

Cheers!

Reply

wondering if there are any plans to use PSR-15-compatible HTTP middleware for authentication.

Reply

Hey azeem!

That's not something we're going to cover, unfortunately. PSR-15 is built on top of PSR-7, which was designed (unfortunately) to be incompatible with Symfony's request/response objects (to be more fair, Symfony could, with some work, change their classes to implement PSR-7, but they don't want to implement it because they/we don't like the dev experience of PSR-7). And so, PSR-15 is awkward to work with in Symfony. There is a bridge that allows it to work - https://symfony.com/doc/cur... - but it's not a main use-case in the Symfony world :).

Cheers!

Reply
akincer Avatar
akincer Avatar akincer | posted 1 year ago

Hey folks really excited for this course. Any updates on when this will start hitting the wire? Just ran into the fact that Guards are now deprecated and wanted to build using the new system for a new project. Thanks!

Reply

Hey Aaron,

Thank you for your interest in SymfonyCasts tutorials! We're releasing a course called "Mastering Doctrine Relations" - it's in the middle right now and will be releasing about 3 week. After that, the next should be "Symfony 5 Security: Authenticators" - it will be based on that "Mastering Doctrine Relations". So, roughly, I think in a month it should be started releasing, at least that's our plan so far :)

Cheers!

Reply
akincer Avatar

Great! I don't know what the odds are of having an LDAP example slipped in to the curriculum might be but that would be great if it could.

Reply

Hey @Aaron!

Unfortunately... that won't be included - it's a bit too specific, and nobody can follow along with it unless they have a handy LDAP server :/. But I know from experience that it can be confusing! There is a built-in LDAP authentication mechanism in Symfony, and one of the cool things in the new security system is that these core classes are much more readable (and thus, if you're having trouble figuring something out, it's much more likely reading the core code can give you a clue). For example, here is the core class that handles the LDAP authentication - https://github.com/symfony/symfony/blob/5.4/src/Symfony/Component/Ldap/Security/LdapAuthenticator.php

This one IS a big more confusing because most of the authentication is done by another authenticator - $this->authenticator. If you're using form_login_ldap - https://symfony.com/doc/current/security/ldap.html#configuration-example-for-form-login - then that "inner" authenticator is https://github.com/symfony/symfony/blob/5.4/src/Symfony/Component/Security/Http/Authenticator/FormLoginAuthenticator.php

But really, the hardest part of LDAP is getting the config & logic for loading the users correct... because an LDAP-powered login form is really just a normal login form that loads users from LDAP instead of a traditional database. Ultimately, when it comes time to load the user from LDAP, this is the class & method that will be responsible for doing that - https://github.com/symfony/symfony/blob/6821b55341c6444b45bf3eeebdffe9a0669daa66/src/Symfony/Component/Ldap/Security/LdapUserProvider.php#L75

So, we won't cover it - but we will cover many things "around" all of this - like custom authenticator and user providers. Hopefully that, along with the links above, will help you out :).

Cheers!

Reply
Robin R. Avatar
Robin R. Avatar Robin R. | posted 1 year ago

Thanx for these great videos, very well made und fully understandable for anyone !
Anyway, it would be very welcome to have one of these videos on "Symfony <> Doctrine <> Elasticsearch" as Elasticsearch is very used for applications and it seems to be a complexe relation between those 3... It could be very useful...
Thank you

Reply

Hey Robin,

Agree, ElasticSearch is great, and commonly used. We even use this for search on SymfonyCasts :) Unfortunately, we don't have too much bandwidth for this course right now, but we definitely want to release this course later, so it's in our idea pool, but no any release date yet.

Thank you for your interest in SymfonyCasts tutorials and your patience!

Cheers!

1 Reply
Default user avatar
Default user avatar asif khan | posted 1 year ago

hi, do you have any plane to add Saas use case in prospective of security?

Reply

Hey asif khan

For the moment we do not have planned to release a tutorial about SaaS but thanks for letting us know what you'd like to learn next

Cheers!

Reply
August S. Avatar
August S. Avatar August S. | posted 1 year ago

Hey Symfonycasts! Been enjoying your tutorials!

Recently I need to add some Users to a site, and was wondering when this tutorial is out? Might wait for this to come out before I make changes to the site.

Reply

Hi @August

Thanks for you interest in us! I suppose it will came after our new doctrine course, but I can't provide you any eta on it =)

Cheers!

Reply

Hey guys, I'm sooo waiting for this tutorial, being a subscriber for 3months - and I must say it's my best investment of all times. The quality of videos and explanation is amazing! I'm sincerely grateful for your job!
Atm have a lesser deadline for a study project, and I'm struggling with a question about email confirmation. Everything seems to work, but even if the user didn't confirmed his email - he is still able to log in. Where and how I could manage this? So the user MUST confirm email, before he able to log in/auto-login after registration. Would be grateful for any replies and tips :)

Reply

Hey Andrejus,

I think you can leverage the User::$enabled property for this, just set it to false by default and users won't be able login anymore. Then, set it to true when users confirmed their emails. But in this case you would need to tweak the default error message that will be shown when users will try to login, but it's easy to do with translations.

Or probably better to create a separate property for this, e.g. "User::$isEmailConfirmed", and check this in your custom user authenticator. If it's not true - you would need to throw an exception to show users an error message explaining why they cannot login.

Btw, I would recommend you to leverage this bundle: https://github.com/SymfonyC... - it has docs explaining how to set up and configure it. We're also going to cover this bundle in our Symfony 5 Security course which in rough might be started releasing in about a month I think :)

I hope this helps!

Cheers!

Reply
Default user avatar
Default user avatar mslimen | posted 2 years ago

Would is be possible to add a example of login after registration using new authentication system , i don't find any example in the internet

Reply

Hi @mslimen

You won't believe how simple is the solution. So after persisting your user to database you should do following things:

  1. wire 2 services to your register action, you can do it directly or whatever method you like
    • Symfony\Component\Security\Http\Authentication\UserAuthenticatorInterface $userAuthenticator
    • App\Security\Authentication\LoginFormAuthenticator $loginFormAuthenticator
  2. now you are ready to authenticate user programmatically so after persisting instead of your response you should return response from authenticator
    
    

class RegistrationController extends AbstractController
{
// ...
public function register(Request $request, UserAuthenticatorInterface $userAuthenticator, LoginFormAuthenticator $loginFormAuthenticator/.../): Response
{

// ...
if ($form->isSubmitted() && $form->isValid()) {
  // ...
  return $userAuthenticator->authenticateUser($newUser, $loginFormAuthenticator, $request)
}
// ...

}
// ...
}



I hope that will help!

Cheers!
Reply
Wlc Avatar

Would is be possible to add a brief example of a registration process to this tutorial? I'm not quite sure if the route belongs in a security controller or its own controller.

Reply

And, to help you out before the tutorial, I usually do put registration in its own controller (separate from security), but I think both places are fine. I'd recommend using make:registration-form from MakerBundle to help you build all of this :).

Cheers!

Reply

Hey wLcDesigns,

Thank you for your interest in SymfonyCasts tutorials! Yes, we're going to cover registration process in this tutorial ;)

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

userVoice