Buy

Guard: Joyful Authentication

My favorite new feature for Symfony 2.8 is Guard. It makes creating custom and crazy authentication systems really really easy. I'm a bit biased: Guard was my creation, inspired by a lot of people and projects.

The Weirdest Login Form Ever

Later, I'll do some in-depth screencasts about Guard, but I want to give you a taste of what's possible. In this project, I have a tradition login system:

42 lines src/AppBundle/Controller/DefaultController.php
... lines 1 - 21
/**
* @Route("/login", name="login")
*/
public function sillyLoginAction()
{
$error = $this->get('security.authentication_utils')
->getLastAuthenticationError();
return $this->render('default/login.html.twig', [
'error' => $error
]);
}
... lines 34 - 42

The /login controller renders a login template and this template builds a form that POSTs right back to that same loginAction:

32 lines app/Resources/views/default/login.html.twig
... lines 1 - 9
<form action="{{ path('login') }}" method="POST">
... line 11
<label for="exampleInputEmail1">Username</label>
<input type="text" name="_username" class="form-control" id="exampleInputEmail1" placeholder="Username">
... lines 14 - 15
<label for="exampleInputPassword1">Password</label>
<input type="password" name="_password" class="form-control"
id="exampleInputPassword1" placeholder="Password">
... lines 19 - 20
<label for="the-answer">The answer to life the universe and everything</label>
<input type="text" name="the_answer" class="form-control" id="the-answer">
... lines 23 - 25
<input type="checkbox" name="terms"> I agree to want to be logged in
... lines 27 - 28
<button type="submit" class="btn btn-default">Login</button>
</form>
... lines 31 - 32

It has a username field, a password field and then a couple of extra fields. One of them is "the answer to life the universe and everything", which of course must be set to 42. The user also needs to check this "agreement" checkbox.

So how can we make a login system that checks four fields instead of just the usual username and password? Hello Guard.

Before coding, start the built-in web server, which is now bin/console server:run:

bin/console server:run

Try out /login.

Creating the Authenticator Class

To use guard, we need a new class. I'll create a new directory called Security, but that's not important. Call the class WeirdFormAuthenticator.Next, make this class implement GuardAuthenticatorInterface or extend the slightly easier AbstractGuardAuthenticator:

44 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 2
namespace AppBundle\Security;
... lines 4 - 10
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
class WeirdFormAuthenticator extends AbstractGuardAuthenticator
{
... lines 15 - 42
}

In PhpStorm, I'll open the generate menu and select "Implement Methods". Select all of them, including start(), which is hiding at the bottom. Also move the start() method to the bottom of the class: it'll fit more thematically down there:

44 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 4
use Symfony\Component\HttpFoundation\Request;
... line 6
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
... lines 11 - 12
class WeirdFormAuthenticator extends AbstractGuardAuthenticator
{
public function getCredentials(Request $request)
{
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
}
public function checkCredentials($credentials, UserInterface $user)
{
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
}
public function supportsRememberMe()
{
}
public function start(Request $request, AuthenticationException $authException = null)
{
}
}

Your job is simple: fill in each of these methods.

getCredentials()

Once we hook it up, the getCredentials() method will be called on the authenticator on every single request. This is your opportunity to collect the username, password, API token or whatever "credentials" the user is sending in the request.

For this system, we don't need to bother looking for the credentials unless the user is submitting the login form. Add an if statement: if $request->getPathInfo() - that's the current, cleaned URL - != /login or !$request->isMethod('POST'), then return null:

101 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 28
public function getCredentials(Request $request)
{
if ($request->getPathInfo() != '/login' || !$request->isMethod('POST')) {
return;
}
... lines 34 - 40
}
... lines 42 - 101

When you return null from getCredentials(), no other methods will be called on the authenticator.

Below that, return an array that contains any credential information we need. Add a username key set to $request->request->get('_username'): that's the name of the field in the form:

101 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 28
public function getCredentials(Request $request)
{
... lines 31 - 34
return [
'username' => $request->request->get('_username'),
... lines 37 - 39
];
}
... lines 42 - 101

Repeat that for password and answer. In the form, answer's name is the_answer and the last is named terms. Finish the array by fetching the_answer and terms:

101 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 28
public function getCredentials(Request $request)
{
... lines 31 - 34
return [
'username' => $request->request->get('_username'),
'password' => $request->request->get('_password'),
'answer' => $request->request->get('the_answer'),
'terms' => $request->request->get('terms'),
];
}
... lines 42 - 101

The keys on the right are obviously the names of the submitted form fields. The keys on the left can be anything: you'll see how to use them soon.

getUser()

If getCredentials() returns a non-null value, then getUser() is called next. I have a really simple User entity that has basically just one field: username:

56 lines src/AppBundle/Entity/User.php
... lines 1 - 11
class User implements UserInterface
{
... lines 14 - 20
/**
* @ORM\Column(type="string")
*/
private $username;
... lines 25 - 54
}

I'm not even storing a password. Whatever your situation, just make sure you have a User class that implements UserInterface and a "user provider" for it that's configured in security.yml:

31 lines app/config/security.yml
... lines 1 - 2
security:
... lines 4 - 5
providers:
my_entity_users:
entity:
class: AppBundle:User
... lines 10 - 31

See the $credentials variable? That's equal to whatever you returned from getCredentials(). Set a new $username variable by grabbing the username key from it:

101 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 17
class WeirdFormAuthenticator extends AbstractGuardAuthenticator
{
... lines 20 - 42
public function getUser($credentials, UserProviderInterface $userProvider)
{
$username = $credentials['username'];
... lines 46 - 53
}
... lines 55 - 99
}

Let's get crazy and say: "Hey, if you have a username that starts with an @ symbol, that's not okay and you can't login". To fail authentication, return null:

101 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 42
public function getUser($credentials, UserProviderInterface $userProvider)
{
$username = $credentials['username'];
// this looks like a weird username
if (substr($username, 0, 1) == '@') {
return;
}
... lines 51 - 53
}
... lines 55 - 101

Now, query for the User! We need the entity manager, so add a private $em property and generate the constructor. Type-hint it with EntityManager:

101 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 5
use Doctrine\ORM\EntityManager;
... lines 7 - 17
class WeirdFormAuthenticator extends AbstractGuardAuthenticator
{
private $em;
... lines 21 - 22
public function __construct(EntityManager $em, RouterInterface $router)
{
$this->em = $em;
... line 26
}
... lines 28 - 99
}

Back in getUser(), this is easy: return $this->em->getRepository('AppBundle:User')->findOneBy() with username equals $username:

101 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 42
public function getUser($credentials, UserProviderInterface $userProvider)
{
$username = $credentials['username'];
... lines 46 - 51
return $this->em->getRepository('AppBundle:User')
->findOneBy(['username' => $username]);
}
... lines 55 - 101

The job of getUser() is to return a User object or null to fail authentication. It's perfect.

checkCredentials()

If getUser() does return a User, checkCredentials() is called. This is where you check if the password is valid or anything else to determine that the authentication request is legitimate.

And surprise! The $credentials argument is once again what you returned from getCredentials().

Let's check a few things. First, the user doesn't have a password stored in the database. In my system, the password for everybody is the same: symfony3. If it doesn't equal symfony3, return null and authentication will fail:

101 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 55
public function checkCredentials($credentials, UserInterface $user)
{
if ($credentials['password'] != 'symfony3') {
return;
}
... lines 61 - 70
}
... lines 72 - 101

Second, if the answer does not equal 42, return null. And finally, if the terms weren't checked, you guessed it, return null. Authentication will fail unless checkCredentials() exactly returns true. So return that at the bottom:

101 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 55
public function checkCredentials($credentials, UserInterface $user)
{
... lines 58 - 61
if ($credentials['answer'] != 42) {
return;
}
if (!$credentials['terms']) {
return;
}
return true;
}
... lines 72 - 101

Handling Authentication Success and Failure

That's it! The last few methods handle what happens on authentication failure and success. Both should return a Response object, or null to do nothing and let the request continue.

onAuthenticationFailure()

The $exception passed to onAuthenticationFailure holds details about what went wrong:

101 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 72
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
... lines 75 - 79
}
... lines 81 - 101

Was the user not found? Were the credentials wrong? Store this in the session so we can show it to the user. For the key, use the constant: Security::AUTHENTICATION_ERROR:

101 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 72
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
$request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception);
... lines 76 - 79
}
... lines 81 - 101

This is exactly what the normal form login system does: it adds an error to this same key on the session.

In the controller, the security.authentication.utils service reads this key from the session when you call getLastAuthenticationError():

42 lines src/AppBundle/Controller/DefaultController.php
... lines 1 - 8
class DefaultController extends Controller
{
... lines 11 - 21
/**
* @Route("/login", name="login")
*/
public function sillyLoginAction()
{
$error = $this->get('security.authentication_utils')
->getLastAuthenticationError();
... lines 29 - 32
}
... lines 34 - 40
}

Other than storing the error, what we really want to do when authentication fails is redirect back to the login page. To do this, add the Router as an argument to the constructor and use that to set a new property. I'll do that with a shortcut:

101 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 9
use Symfony\Component\Routing\RouterInterface;
... lines 11 - 17
class WeirdFormAuthenticator extends AbstractGuardAuthenticator
{
... line 20
private $router;
public function __construct(EntityManager $em, RouterInterface $router)
{
... line 25
$this->router = $router;
}
... lines 28 - 99
}

Now it's simple: $url = $this->router->generate() and pass it login - that's the route name to my login page. Then, return a new RedirectResponse:

101 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 72
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
... lines 75 - 76
$url = $this->router->generate('login');
return new RedirectResponse($url);
}
... lines 81 - 101

onAuthenticationSuccess()

When authentication works, keep it simple and redirect back to the homepage. In a real app, you'll want to redirect them back to the previous page:

101 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 81
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
$url = $this->router->generate('homepage');
return new RedirectResponse($url);
}
... lines 88 - 101

There's a base class called AbstractFormLoginAuthenticator that can help with this.

start() - Inviting the User to Authentication

The start() method is called when the user tries to access a page that requires login as an anonymous user. For this situation, redirect them to the login page:

101 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 88
public function start(Request $request, AuthenticationException $authException = null)
{
$url = $this->router->generate('login');
return new RedirectResponse($url);
}
... lines 95 - 101

supportsRememberMe()

Finally, if you want to be able to support remember me functionality, return true from supportsRememberMe():

101 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 95
public function supportsRememberMe()
{
return true;
}
... lines 100 - 101

You'll still need to configure the remember_me key in the firewall.

Configuring the Authenticator

That's it! Now we need to tell Symfony about the authentication with two steps. The first shouldn't surprise you: register this as a service. In services.yml create a new service - how about weird_authenticator. The class is WeirdFormLoginAuthenticator and there are two arguments: the entity manager and the router:

10 lines app/config/services.yml
... lines 1 - 5
services:
weird_authenticator:
class: AppBundle\Security\WeirdFormAuthenticator
arguments: ['@doctrine.orm.entity_manager', '@router']

Finally, hook this up in security.yml. Under your firewall, add a guard key and an authenticators key below that. Add one authenticator - weird_authenticator - the service name:

31 lines app/config/security.yml
... lines 1 - 2
security:
... lines 4 - 10
firewalls:
... lines 12 - 16
main:
anonymous: ~
... lines 19 - 21
guard:
authenticators:
- weird_authenticator
... lines 25 - 31

Now, getCredentials() will be called on every request. If it returns something other than null, getUser() will be called. If this returns a User, then checkCredentials() will be called. And if this returns true, authentication will pass.

Test the Login

Try it out! With a blank form, it says Username could not be found. It is looking for the credentials on the request, but it fails on the getUser() method. I do have one user in the database: weaverryan. Put symfony3 for the password but set the answer to 50. This fails with "Invalid Credential". Finally, fill in everything correctly. And it works! The web debug toolbar congratulates us: logged in as weaverryan.

Customize the Error Messages

We saw two different error messages, depending on whether authentication failed in getUser() or checkCredentials(). But you can completely control these messages by throwing a CustomUserMessageAuthenticationException(). I know, it has a long name, but it's job is clear: pass it the message you want want to show the user, like:

108 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 12
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
... lines 14 - 43
public function getUser($credentials, UserProviderInterface $userProvider)
{
... lines 46 - 48
if (substr($username, 0, 1) == '@') {
throw new CustomUserMessageAuthenticationException(
'Starting a username with @ is weird, don\'t you think?'
);
}
... lines 54 - 56
}
... lines 58 - 108

Below if the answer is wrong, do the same thing: throw new CustomUserMessageAuthenticationException() with:

108 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 58
public function checkCredentials($credentials, UserInterface $user)
{
... lines 61 - 64
if ($credentials['answer'] != 42) {
throw new CustomUserMessageAuthenticationException(
'Don\'t you read any books?'
);
}
... lines 70 - 77
}
... lines 79 - 108

And in case the terms checkbox isn't checked, throw a new CustomUserMessageAuthenticationException and threaten them to agree to our terms!

108 lines src/AppBundle/Security/WeirdFormAuthenticator.php
... lines 1 - 58
public function checkCredentials($credentials, UserInterface $user)
{
... lines 61 - 70
if (!$credentials['terms']) {
throw new CustomUserMessageAuthenticationException(
'Agree to our terms!!!'
);
}
return true;
}
... lines 79 - 108

Try it out with @weaverryan. There's the first message! Try 50 for the answer: there's the second message. And if you fill in everything right but have no checkbox, you see the final message.

That's Guard authentication: create one class and do whatever the heck that you want. I showed a login form, but it's even easier to use for API authentication. Basically, authentication is not hard anymore. Invent whatever insane system you want and give the user exactly the message you want. If you want to return JSON on authentication failure and success instead of redirecting, awesome, do it.

Leave a comment!

  • 2016-08-22 Victor Bocharsky

    Hey Nicolas,

    This's difficult to answer without some debugging :). The most common error here is that you could missed return statement in your FormLoginAuthenticator, i.e. you get an User object from DB but forget to *return* it. So, first of all, check all necessary return statements in FormLoginAuthenticator methods. If everything is find, well, debug your code step by step starts from the fist method. I'd recommend to simply use "dump(); die;", dump the result which every method should return and compare this actual result with an expected result.You'll figure out some cases, i.e. you forget to return valid credentials or your DB query is invalid and don't return an User object etc. In this way you can realize on what method you stuck.

    If this didn't help you - provide a bit more information for us like what method wasn't called, etc. and we try to help you with it.

    Cheers!

  • 2016-08-20 Nicolas

    Hi,
    Thanks for the tutorial.
    I did the tutorial but i can't login in, i am everything look great but when i am going back to "homepage" i am still log as anonymous. No error message.

    Any Suggestion ?

  • 2016-07-15 weaverryan

    Yes, this is a really important detail - one that we use here on our site!

    Here's the trick: use the TargetPathTrait and call the getTargetPath() method: https://github.com/symfony/sym.... This is new in Symfony 3.1 - but no problem: if you're on an earlier version, simply copy that small function into your code.

    Here's what's going on:

    A) When you try to access some secure page (e.g. /admin) and are redirected to the login page (or more accurately, the start() method in one of your authenticators redirects the user to the login page), Symfony automatically stores this URL (/admin) in the session under a very specific key.

    B) The TargetPathTrait::getTargetPath() function is just a helper for you to read this key from the session.

    Let me know if it works! We also do this same thing after registration - since the user might choose to register instead of logging in ;).

    Cheers!

  • 2016-07-14 dlegatt

    It didnt work, I just sit at the login page now. Here is what my main firewall looks like. I didnt have the form_login section before, i added it so I could have the use_referer option. Without that, I got an error when the controller returned null.


    main:
    pattern: ^/
    anonymous: ~
    logout:
    path: /logout
    target: /
    form_login:
    use_referer: true
    login_path: /admin/login
    check_path: /admin/login_check
    guard:
    provider: admin_user_provider
    authenticators:
    - app.authenticator.form
  • 2016-07-14 Victor Bocharsky

    Hey dlegatt ,

    If I recall correctly, you should return null in your `onAuthenticationSuccess()` and it will work out of the box. Could you try it? If it still does not work, force it with enabling use_referer option. I think it should help.

    Cheers!

  • 2016-07-13 dlegatt

    Hi Ryan! I really love the guard component, it has helped make security in my app much simpler to set up and maintain. One of my guard authenticators is a traditional form login. Right now, when someone is redirected to the login page after trying to reach a secure page, I have the onAuthenticationSuccess method redirect them to the index page of the secured area. How can I direct them to the page the requested before logging in?

  • 2016-05-13 weaverryan

    Hi there!

    If you use - dump($credentials);die; - then you should be able to debug like any normal situation. You likely will need the die, since if you fail authentication, you are probably redirecting the user to another page. If you still don't see the dump, then you are somehow *not* reaching checkCredentials().

    Another thing to look at is to temporarily turn on "intercept_redirects" in config_dev.yml (you should see it there already, commented-out). When you do this, instead of redirecting, Symfony will *stop* and show you a page. On this page, you will see the web debug toolbar for the current request (the one that is redirecting the user). You can see the dump() there, and any other information.

    Cheers!

  • 2016-05-13 rddro

    How can I debug inside these methods ?
    For example in checkCredentials i want to dump the $credentials but it's not working :(

  • 2016-03-24 weaverryan

    Hi Andrzej!

    Yes, it *is* good to clear your plan password in eraseCredentials - it just makes sure that the plain password doesn't accidentally get stored anywhere, like the session. Symfony automatically calls this after you login. You just need to make sure that you don't also clear the password field :). In this case, in eraseCredentials(), I would directly set $this->plainPassword = null - instead of calling setPlainPassword(). That should also fix the problem.

    Cheers and thanks for sharing!

  • 2016-03-23 Andrzej

    I found the reason of this problem, it was cause because of setPlainPassword() and eraseCredentials() methods in User class. I found in Symfony documentation that it is good co clear plainPassword for security reasons. Commenting out $this->setPlainPassword(null); fixes the problem.




    public function setPlainPassword($plainPassword)

    {

    $this->plainPassword = $plainPassword;

    $this->setPassword(null);

    }

    public function eraseCredentials()

    {

    $this->setPlainPassword(null);

    }



  • 2016-03-22 weaverryan

    Hmm, curious - that is *not* the problem then. Does your user implement AdvancedUserInterface by chance?

  • 2016-03-22 Andrzej

    Hello, this is my getRoles() method


    public function getRoles()

    {

    $roles = $this->roles;

    $roles[] = 'ROLE_USER';

    return array_unique($roles);

    }

    Here is screen from my toolbar

    http://www.awesomescreenshot.c...

  • 2016-03-21 weaverryan

    Hey Andrzej!

    I'm glad you solved the first problem :). About the second problem, what does your getRoles() method look like in your User class? Make sure that it *always* returns at least *one* role. If you return zero roles from getRoles(), then you will see this behavior. Let me know if that's the problem!

    Cheers!

  • 2016-03-21 Andrzej

    I solved the problem with encoded password, I made mistake in my fixtures and I was encoding password not plain password. But I still can't find out why when i log in in toolbar I see
    Loggedin: admin
    Authenticated: No

  • 2016-03-18 Andrzej

    Hello,

    I am implementing custom authentication with guard end everything works fine until I create password encoding. To encode password I use doctrine event listeners (I pass @security.password_encoder as a servcie argument) and I encode password this way




    $password = $this->userPasswordEncoder->encodePassword($user, $user->getPlainPassword());

    $user->setPassword($password);



    And then inside FormLoginAuthenticator I check password in checkCredentials method




    public function checkCredentials($credentials, UserInterface $user)

    {

    if($this->userPasswordEncoder->isPasswordValid($user, $credentials['password'])) {

    return true;

    }

    throw new CustomUserMessageAuthenticationException('Wrong password');

    }



    And here i have the problem becasue it alwys return false. I tried to expermient with password encoding and i did dump() of

    $this->userPasswordEncoder->encodePassword($user, 'admin123'); a couple of times and it always returned different string. I wonder what I am doing wrong?

    When I get rid of password encoding and i save plain password in datase authentication works fine, except the fact that in symfony toolbar i see:

    Loggedin: admin

    Authenticated: No

    What might be the reason of this?

  • 2016-03-11 Tanariel

    Thanks much for your answer, it does help indeed :)

  • 2016-03-10 weaverryan

    Hi there!

    Really good questions :). Let me try to help:

    1) I don't usually use a Symfony form for a login form - I feel it's overkill. But, it's certainly not wrong.

    2) Yes, I would submit the form in getCredentials(), and then return the array of data from that method (or an object, if you have your form bound to an object).

    3) How to send back the errors, is a little more difficult. If the form is not valid, I would probably save the form into the request object and then fail authentication (all in getCredentials()):


    if (!$form->isValid()) {
    $request->attributes->set('login_form', $form);
    }

    Then, in onAuthenticationFailure(), I would do nothing: allow the request to *continue* to your controller. Make sure that the URL you submit your form to (e.g. /login) is the same URL that *displays* your login form. That way, by doing nothing in onAuthenticationFailure, the request will continue and will call your loginAction (the one that displays your form). Here, look for the Form in the Request and use it:


    public function loginAction(Request $request)
    {
    if ($request->attributes->has('login_form')) {
    $form = $request->attributes->get('login_form');
    $request->attributes->remove('login_form');
    } else {
    $form = $this->createForm(...);
    }

    // ... all your normal logic
    }

    If authentication fails, you will use the form that was stored (temporarily) on the request: this will have all the normal, bound errors.

    For me - this isn't worth the trouble :). But it certainly will work just fine.

    4) If you have a chain of authenticators, each of them should be authenticating in a different way - e.g. one for form login, one for API key authentication etc. So, think only your "form login" authenticator would have a form - the others would just do whatever *they* need to do.

    I hope that helps!

    Cheers!

  • 2016-03-10 Tanariel

    Hi everyone !

    Thanks for guard, it's really a nice way to make authentication simpler.

    I have a question about it though, i'm trying to use a form type as login form, but i can't figure out where the form should be validated ? At start of the guard class in getCredentials() ? If so, how would i be able to send back the error list of the form ?

    Is it a bad practice to go for a form type for login form ?

    If i use a chain of guard authenticators, would the form need to be validated on every getCredential() ?

    Thanks in advance if any of you have answer / advice about this.
    And thanks again for those nice tutorials :)

  • 2016-01-15 Reynier Pérez Mira

    Hi there weaverryan I think this is already bundle in latest Symfony 2.8 and 3.0 I am right? Also I would like to know if this component could help me to achieve what I am trying to do. Can you take a look to this post: How to create “two” (chat and admin) or more secured areas with FOSUserBundle (http://stackoverflow.com/quest... in SO and tell me if this can be achieved with Guard?

  • 2015-12-28 weaverryan

    Boom! I love the feedback - thanks for sharing Daniel :)

  • 2015-12-27 Daniel

    Thanks Ryan! Just use it for an API and it works like a charm!

  • 2015-12-18 Jovan Perović

    Very nice tutorial! Clean cut :)

  • 2015-11-18 Léo Li

    Good introduction, that's exactly what I want to use for my project! Thank you!