Symfony Security: Beautiful Authentication, Powerful Authorization

Ah, security! Quick run!

Wait, come back! Security in Symfony is awesome! Seriously, between things called "voters" and the Guard authentication system, you can do anything you want inside of Symfony, and the code to do it is simple and expressive.

Security has two sides: authentication (who are you?) and authorization (do you have access to do X). We'll talk about each of these, creating an traditional form login system and and API token authentication system using Json web tokens (not as scary as they sound!). Then, we'll turn to authorization, with roles, voters and other good stuff:

  • Security & Firewall Fundamentals
  • Creating a custom login form
  • Making a User (ooOOOoo)
  • User Providers (why you need them, but don't care)
  • Password Encryption
  • Logging out!
  • Protecting entire URLs with access_control(s)
  • IS_AUTHENTICATED_FULLY, IS_AUTHENTICATED_REMEMBERED
  • Checking access with roles! ROLE_USER
  • Denying access in a controller
  • What are voters?
  • Role hierarchies
  • Impersonation (switch_user)
  • Registration Form
  • Manual authentication

... and how to create a back door into your site. Just kidding! Let's make some secure sites!


Your Guides

Ryan Weaver Leanna Pelham

Questions? Conversation?

  • 2016-10-18 weaverryan

    Yo Mike!

    It's not in this tutorial, but it is right here: https://knpuniversity.com/scre... and also here: https://knpuniversity.com/scre.... The first is more up-to-date (after we made a simplification to voters) but the second has a little bit more background detail. Voters are awesome... so enjoy!

    Cheers!

  • 2016-10-18 Mike Milano

    Voters are mentioned in the description but are they covered here? If so, which video are they covered in?

    It's been a while since I've done this course and I'd like to skip to content relevant to voters.

  • 2016-09-19 weaverryan

    That's probably not a bad idea - I try to avoid Doctrine listeners if I can, and instead do work in services, and call those services when needed. Doctrine is great, but Doctrine listeners are a weird place, where you're already right in the middle of saving something. Not a bad policy to avoid :).

    Cheers!

  • 2016-09-18 Lee Ravenberg

    Thanks Ryan! I really appreciate you taking the time to look at it.

    I finally decided to remove the doctrine Password Hash Listener and encode the passwords at an other place. This works fine. I am still curious about what the cause of the issue is though. Doctrine scares me.

  • 2016-09-12 weaverryan

    Yo Lee!

    Haha, sorry to disappoint ;). Once you've got authenticators down, you're a pro. Well, there's *always* more to security :).

    I just left a comment on your SO - it's definitely something minor: based on your post, I think you understand things really well. I actually *always* call persist() - even though I don't need to - so I'm less familiar with what might ultimately be causing it.

    Cheers!

  • 2016-09-12 Lee Ravenberg

    Followed the entire course and learned a lot! Authentication is awesome. When I finished the last video I really went like 'doh.. are we done already?'. So I went on to build a Password Reset form by making a LoginHash entity. But I ran into a problem when storing the new password into the database. If anyone is curious, I made a Stackoverflow post here: http://stackoverflow.com/quest...

  • 2016-09-02 weaverryan

    Ah, good find! I've totally done that sort of thing before :D

    Cheers!

  • 2016-09-02 Shane MAIAU

    I'm so dumb, it's was a mistake in my code.

    In my User entity i wrote this code :
    public function getPassword()
    {
    return $this->getPassword();
    }

    that's why i have an infinite loop.

    Thanks again for your time and your support you rocks !

  • 2016-09-02 weaverryan

    Yo Shane!

    Ah, well good debugging at least with the "intercept redirect"! That helps narrow things down. What's the 500 error message that you get after the redirect? It definitely makes me think that something is misconfigured with your "user provider" - http://knpuniversity.com/scree....

    And thanks for the nice words - it makes it a lot more fun for us when this stuff is really useful to people!

    Cheers!

  • 2016-09-02 Shane MAIAU

    Hi Ryan,

    I have a weird error and I still figuring out why I have this issue.
    I created my Authenticator and I can login.

    When I intercept the redirect, I can see that my login form is working but when I redirect to the homepage I have an error 500.

    I don't know why maybe I have an infinite loop after the login ?

    Thanks again for your help and your amazing tutorials.

    Shane

  • 2016-08-16 Vlad

    Thank you, Ryan, that's great! I'll shoot you an email, once I finish the course!

  • 2016-08-15 weaverryan

    Hey Vlad!

    This is something we're actually working on right now (and your feedback about what you need on the certificate is very useful!). But, we'd be happy to make a certificate for you before then so you have it. Just send us an email (hello@unviersity.com) with the details (e.g. your full name).

    Happy this topic hit on your continuing ed requirements - that's awesome :).

    Cheers!

  • 2016-08-15 Vlad

    Hi Ryan,
    Is there any way to get a completion certificate?
    This course is perfect for renewal of one of my certifications as part of continuing education, but I need to provide a completion certificate with the course name and my full name on it.
    Thank you!

  • 2016-07-20 weaverryan

    These are awesome resources - thanks for sharing them :). And yes, we would definitely do this on Symfony 3!

  • 2016-07-19 Chen Dong

    Hi Ryan, thanks for the reply. I think I have got some real world examples for you and this might be (may not be) seem like a challenge... But we'll be so happy if you accept this challenge; BTW, will it be possible to experimenting them on Symfony3 framework as well? Many thanks and the best regards! :-)

    Push it to the limits - Symfony2 for High Performance needs:
    http://symfony.com/blog/push-i...

    Handling 1 Billion requests a week with Symfony2:
    http://labs.octivi.com/handlin...

    The Easy Way Of Building A Growing Startup Architecture Using HAProxy, PHP, Redis And MySQL To Handle 1 Billion Requests A Week:
    http://highscalability.com/blo...

  • 2016-07-19 weaverryan

    Hey Chen!

    Ah, thank you! I think this a great topic - more and more people are asking for something like this. Which parts are most important to you? Tuning the bottom-line speed of each request? Caching? Something else?

    I'm adding it to our list right now :).

    Cheers!

  • 2016-07-19 Victor Bocharsky

    Hey Chen,

    We don't plan any "Symfony Optimization" courses in the near future. Usually, a performance optimization inversely to the maintenance, I mean, that if you optimized performance of your application very cool, probably, you will find it difficult to maintenance code of this application and make some changes in the future. I would advise you to look in the direction of cache like Symfony HTTP cache which provides out of the box, or more complex solutions like Memcache or Redis.

    You also could probably check the Blackfire.io, which is a cool profiler tool. It allows you to find a bottleneck in your application and helps to find a proper solution how to improve performance of your application.

    Cheers!

  • 2016-07-19 Victor Bocharsky

    Hey,

    You can simply check if user has a role in templates with "is_granted()" Twig function along with "include" Twig tag and then render different templates based on result of condition. For example:

    {% if is_granted('ROLE_MANAGER') %}
    {% include '_manager.html.twig' %}
    {% else %}
    {% include '_default.html.twig' %}
    {% endif %}

    Or even add the same conditions in your action and render different templates based on user role.

    Sometimes it's useful to have different actions/routes in controller for different roles, but anyways, you will have to add conditions to build links to these different routes.

    If your users have a lot of roles, probably you need to think about custom Voters or even Symfony ACL.

    Cheers!

  • 2016-07-19 Chen Dong

    Hi Ryan and Leanna, I just wanted to say thank you for all the amazing tuts, I'm just wondering will there be any tuts regarding to Symfonys' Performance Tuning in the future?

  • 2016-07-16 JLChafardet

    Hey guys! sorry to ask something that maybe has already been asked but.

    based on the roles here, can I render specific views?

    lets not go to super granulated permissions, that seems to be a really tiresome-bothersome-painintheassish task, but roles based, could that be managed in a "if user belongs to X role" render this view, else render this other?

    I'm aware i can hide specific areas in views based on that, tho, what about views that would significantly change? having that bunch of conditions wouldnt be a pain?

  • 2016-07-15 Chen Dong

    Your Courses about Symfony are amazing, I'm wondering will there be any tuts related to Symfony Optimization coming in the Future? Cause I personally think that the optimized environment or configuration or code might be faster than the default.

  • 2016-07-15 Victor Bocharsky

    I think I know why: "isXmlHttpRequest()" works if your JavaScript library sets an X-Requested-With HTTP header. It is known to work with common JavaScript frameworks. But if this header wasn't passed - it won't work, so you need to add another custom check for it.

    Cheers!

  • 2016-07-14 fredrsf

    Hi Victor Bocharsky , yes i tried to do it as this tutorial. I used 'fetch' from es6 and my user stayed anonimus (I don't understood why). When i change it to XMLHttpRequest, registration works correct. Thank you!!!

  • 2016-07-14 Victor Bocharsky

    Hey fredrsf ,

    Did you see the latest chapter in this course: Automatically Login after Registration. It explain how to do it, except that you should wrap `$this->get('security.authentication.guard_handler')->authenticateUserAndHandleSuccess(...)` call with additional condition:

    if ($request->isXmlHttpRequest()) {
    return $this->get('security.authentication.guard_handler')
    ->authenticateUserAndHandleSuccess(...);
    }

    If you'll send an AJAX request - `isXmlHttpRequest()` returns true in this case. And don't forget to handle that case when you have a normal (not AJAX) request.

    Cheers!

  • 2016-07-14 fredrsf

    Hello everyone, how can i do automatically login after registration, if registration form data came from ajax request?

  • 2016-06-29 JLChafardet

    lets hope the rest comes soon enough!

  • 2016-06-28 JLChafardet

    oh at last! cant wait to get started.

  • 2016-06-22 weaverryan

    Good news Bjorn - next week! We're doing final edits on it right now :)

    Cheers!

  • 2016-06-22 Bjorn Larson

    Please I need this tutorial. when is it coming out ???

  • 2016-06-20 Victor Bocharsky

    We'll have a script content without code blocks first. Code blocks will be added a bit later, after screencasts.

  • 2016-06-18 JLChafardet

    Thats amazing! indeed would be awesome to be able to start even without the screencast, with the scripts maybe?

  • 2016-06-18 weaverryan

    This will be released the week after next (so about 9 days) - but parts of it may be released next week :)

  • 2016-06-17 Victor Bocharsky

    Ah, OK!

    If you have not found any solution yet, could you explain me again what exactly don't work as you want in this code? I'll try to help you with it too.

    Cheers!

  • 2016-06-16 Julian

    This works the same way as the Controller before. There is still a default render to /login but I will check out now how to customize the Routes after a logout. Thank you so much and I'm also thankfull for any further advices!

  • 2016-06-16 Victor Bocharsky

    Hey, do you consider isGranted('IS_AUTHENTICATED_REMEMBERED')? It returns true for all logged in users, even if they are logged in because of a "remember me cookie". (Notice that I don't use negation (! sign) in if statement):


    public function loginAction()
    {
    if ($this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
    return $this->render('MainBundle:Default:show.html.twig');
    }

    return $this->render('MainBundle:Default:log_index.html.twig');
    }

    Please, let me know if it helps you!

  • 2016-06-16 Julian

    Thanks a lot dude! It was definitly my own YML mistake. I just have still a routingproblem. When my auth_token is set Annonymous my project is still rendering the default login form. When I have authorization he renders the show.html I just want to have rendered there ;). My dream is to render the log_index.html if a user logsout or is at the Annonymous-Status.

  • 2016-06-16 Victor Bocharsky

    BTW, you could check full security reference here http://symfony.com/doc/current..., or just use Symfony console command:

    bin/console config:dump-reference security
  • 2016-06-16 Victor Bocharsky

    Hey, Julian!

    What about the second problem, it's difficult to understand from your message without proper formatting, but I was tricky and was able to see what's the problem :) You placed `anonymous` key under `logout` but should under your firewall name like:


    your_firewall_name:
    logout:
    path: /logout
    target: /log_index
    anonymous: true

    Please, fix it first and let me know if your first issue still exist.

    Cheers!

  • 2016-06-16 Julian

    Hi Guys! I'm using the FOSUserBundle and I have two Problems while logging out.
    1.
    I have set up a MainController and I want to have a different view for ppl who are logged in. So I let my MainController do this:


    /**
    * @Route("/")
    */
    public function loginAction()
    {
    if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY'))
    {
    return $this->render('MainBundle:Default:log_index.html.twig');
    }
    else
    {
    return $this->render('MainBundle:Default:show.html.twig');
    }

    }


    It kinda works BUT when I log out there is the default login page rendered and not my own log_index.html what I want to render when a user logs out.

    2. Problem is using the firewall correctly
    When I want my firewall to handle logouts like that:


    logout:
    path: /logout
    target: /log_index
    anonymous: true


    Symfony throws Excetions like I'm using the wrong option there..

    Maybe you can help me.

    Cheers!

  • 2016-06-15 JLChafardet

    Oh well anxiously waiting for this tutorial series to be released! I learnt a lot from Starting in Symfony 3 series, cant wait to get to this new part!

  • 2016-06-04 Jan R.

    Hey, Ryan. Thanks for great tutorials. Helped very much to master Symfony! Watched them on one breath! Can't wait for Security tutorial to be released. Keep going on!

  • 2016-05-19 weaverryan

    Thank you so much for this! And you also highlighted some problems with the official docs that we can fix :).

    I have added this to our internal screencast idea list. There's no public place to vote for ideas currently. Well, no "official" place - often times people click the "Ideas or Feedback" button on the bottom right of the page and add the idea there. Other people vote on those. We've been thinking about adding a proper spot on the site - it would be great to crowdsource what people are having most trouble with!

    Cheers!

  • 2016-05-19 Yoni L.

    Ok, to begin, most of the tutorials available describe how to use translator from scratch [http://symfony.com/doc/2.8/com...], but the translator service is already active and the name is "translator.default" for injection.

    - The fact that symfony can manage and create the file they are always talking about in that tutorials (xml, po, array...) with the console.

    I know that we can use anything to render view but we can suppose that we use the excellent twig part.
    I use {%trans%} in twig, how to generate easily the translation file in fr_FR and en_GB for example and where is it created?
    I was force to google that (or Bing or yahoo...) to finaly understand: It's so easy...
    - the translation folders which is a very sensitive point of 3 lines in the doc

    If i was looking for a tutorial, I would like to have:
    - quick overview of the global process
    - (how to) the front end translation (twig),
    - (how to) the back end translation (for api, ajax, error thrown...).
    - the awesome translation file generation and the console debuging.
    - ice on the cake for fun: custom translator with twig filter.

    Often when already have some text to translate, and the official doc is beginning at the opposite of that.
    Do we have a sugestion page on the KnPU site with vote?

  • 2016-05-19 weaverryan

    Hi Yoni!

    We don't have an active plan to talk about translations, but it's a good topic! I would love to know what specific pieces were most difficult for you - we could use that to plan the tutorial!

    Cheers!

  • 2016-05-18 Yoni L.

    Hi Ryan and Leanna,
    Did you plan a tutorial for translation service? I spent so much time to find usefull and up-to-date infos on the official doc, it could be usefull.

    Thanks

  • 2016-05-18 weaverryan

    So glad you asked :). Yes, definitely June, hopefully early. I've already coded it up and will start recording soon (just need to get forms and Symfony REST part 5 out the door first).

  • 2016-05-15 Raphael Schubert

    Any scheduled date to this tutorial??

  • 2016-03-29 weaverryan

    I have a few other tutorials scheduled before this one, so it won't be in April :/. BUT, *very* soon, we'll be releasing the new Symfony REST course about security, and I think you might be able to use some good things from it :). http://knpuniversity.com/scree...

    If you hit the "Notify me" button at the top - we'll send you a one-time email when this course comes out.

    Cheers!

  • 2016-03-27 Damir Rama

    Hi Ryan, can you tell me when this tutorials come out? Thx for the work. It's greeeat!

  • 2016-03-24 cool

    Looking forward to this tutorial

  • 2016-03-21 weaverryan

    Aaawesome :)

  • 2016-03-21 Yuriy Stenin

    Hi, thanks for your great courses. I've been inspired your courses and creates own simple app for blogging http://demo-app.dev.htmlcms.me... I Am beginner in symfony

  • 2016-02-25 Léo Li

    LOOKING FORWARD TO THIS

  • 2016-01-13 Felipe Martins

    Nice Ryan!
    I'm looking forward to watching that serie in the next.. :)