symfony guard authentication: fun with api token, social login, jwt and more

114
Guard Authentication: Powerful, Beautiful Security by your friend: Ryan Weaver @weaverryan

Upload: ryan-weaver

Post on 16-Apr-2017

13.260 views

Category:

Technology


32 download

TRANSCRIPT

Page 1: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Guard Authentication: Powerful, Beautiful Security

by your friend:

Ryan Weaver @weaverryan

Page 2: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

KnpUniversity.comgithub.com/weaverryan

Who is this guy?

> Lead for the Symfony documentation

> KnpLabs US - Symfony Consulting, training & general Kumbaya

> Writer for KnpUniversity.com Tutorials

> Husband of the much more talented @leannapelham

Page 3: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

KnpUniversity.com

Page 4: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

KnpUniversity.com

Page 5: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

KnpUniversity.comgithub.com/weaverryan

Who is this guy?

> Lead for the Symfony documentation

> KnpLabs US - Symfony Consulting, training & general Kumbaya

> Writer for KnpUniversity.com Tutorials

> Husband of the much more talented @leannapelham

Page 6: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

What’s the hardestpart of Symfony?

@weaverryan

Page 7: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Authentication*

Who are you?

@weaverryan

*I am hard

Page 8: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Authorization

Do you have access to do X?

@weaverryan

Page 9: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

VOTERS!

@weaverryan

Page 10: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Authenticationin Symfony sucks?

@weaverryan

Page 11: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

1) Grab information from the request

@weaverryan

Page 12: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

2) Load a User

@weaverryan

Page 13: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

3) Validate if the credentials are valid

@weaverryan

Page 14: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

4) authentication success…now what?

@weaverryan

Page 15: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

5) authentication failure …dang, now what?!

@weaverryan

Page 16: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

6) How do we “ask” the user to login?

@weaverryan

Page 17: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

6 Steps

5 Different Classes

@weaverryan

Page 18: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

security: firewalls: main: anonymous: ~ logout: ~ form_login: ~ http_basic: ~ some_invented_system_i_created: ~

Each activates a system of these 5 classes

@weaverryan

Page 19: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Authenticationin Symfony sucks?

@weaverryan

Page 20: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

On Guard!

@weaverryan

Page 21: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

interface GuardAuthenticatorInterface{ public function getCredentials(Request $request); public function getUser($credentials, $userProvider); public function checkCredentials($credentials, UserInterface $user); public function onAuthenticationFailure(Request $request); public function onAuthenticationSuccess(Request $request, $token);

public function start(Request $request); public function supportsRememberMe();}

@weaverryan

Page 22: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Bad News…

@weaverryan

Page 23: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

You still have to do work!

@weaverryan

and wear sunscreen!

Page 24: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

But it will be simple

@weaverryan

https://github.com/knpuniversity/guard-presentation

Page 25: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

You need a User class

(This has nothing todo with Guard)

@weaverryan

Page 26: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

@weaverryan

use Symfony\Component\Security\Core\User\UserInterface; class User implements UserInterface{ }

Page 27: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

class User implements UserInterface{ private $username; public function __construct($username) { $this->username = $username; } public function getUsername() { return $this->username; } public function getRoles() { return ['ROLE_USER']; } // …}

a unique identifier(not really used anywhere)

Page 28: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

@weaverryan

class User implements UserInterface{ // … public function getPassword() { } public function getSalt() { } public function eraseCredentials() { }}

These are only used for users thathave an encoded password

Page 29: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

The Hardest Example Ever:

Form Login

@weaverryan

☼☼

Page 30: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

A traditional login form setup

@weaverryan

Page 31: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

class SecurityController extends Controller{ /** * @Route("/login", name="security_login") */ public function loginAction() { return $this->render('security/login.html.twig'); } /** * @Route("/login_check", name="login_check") */ public function loginCheckAction() { // will never be executed } }

Page 32: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

<form action="{{ path('login_check') }}” method="post"> <div> <label for="username">Username</label> <input name="_username" /> </div> <div> <label for="password">Password:</label> <input type="password" name="_password" /> </div> <button type="submit">Login</button> </form>

Page 33: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Let’s create an authenticator!

@weaverryan

Page 34: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

class FormLoginAuthenticator extends AbstractGuardAuthenticator{ public function getCredentials(Request $request) { } public function getUser($credentials, UserProviderInterface $userProvider) { } public function checkCredentials($credentials, UserInterface $user) { } public function onAuthenticationFailure(Request $request) { } public function onAuthenticationSuccess(Request $request, TokenInterface $token) { } public function start(Request $request, AuthenticationException $e = null) { } public function supportsRememberMe() { }}

Page 35: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function getCredentials(Request $request) { if ($request->getPathInfo() != '/login_check') { return; } return [ 'username' => $request->request->get('_username'), 'password' => $request->request->get('_password'), ];}

Grab the “login” credentials!

@weaverryan

Page 36: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function getUser($credentials, UserProviderInterface $userProvider) { $username = $credentials['username']; $user = new User(); $user->setUsername($username); return $user; }

Create/Load that User!

@weaverryan

Page 37: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function checkCredentials($credentials, UserInterface $user) { $password = $credentials['password']; if ($password == 'santa' || $password == 'elves') { return; } return true;}

Are the credentials correct?

@weaverryan

Page 38: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function onAuthenticationFailure(Request $request, AuthenticationException $exception) { $url = $this->router->generate('security_login'); return new RedirectResponse($url);}

Crap! Auth failed! Now what!?

@weaverryan

Page 39: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) { $url = $this->router->generate('homepage'); return new RedirectResponse($url);}

Amazing. Auth worked. Now what?

@weaverryan

Page 40: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function start(Request $request) { $url = $this->router->generate('security_login'); return new RedirectResponse($url); }

Anonymous user went to /adminnow what?

@weaverryan

Page 41: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Register as a service

services: form_login_authenticator: class: AppBundle\Security\FormLoginAuthenticator autowire: true

@weaverryan

Page 42: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Activate in your firewall

security: firewalls: main: anonymous: ~ logout: ~ guard: authenticators: - form_login_authenticator

@weaverryan

Page 43: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

User Providers

(This has nothing todo with Guard)

@weaverryan

☼☼ ☼

Page 44: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Each App has a User class

@weaverryan

And the Christmas spirit

Page 45: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Each User Class Needs 1 User Provider

@weaverryan

Page 46: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

class SunnyUserProvider implements UserProviderInterface{ public function loadUserByUsername($username) { // "load" the user - e.g. load from the db $user = new User(); $user->setUsername($username); return $user; } public function refreshUser(UserInterface $user) { return $user; } public function supportsClass($class) { return $class == 'AppBundle\Entity\User'; }}

Page 47: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

services: sunny_user_provider: class: AppBundle\Security\SunnyUserProvider

@weaverryan

Page 48: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

security: providers: sunnny_users: id: sunny_user_provider firewalls: main: anonymous: ~ logout: ~ # this is optional as there is only 1 provider provider: sunny_users guard: authenticators: [form_login_authenticator]

Boom!

Optional Boom!

Page 49: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

class SunnyUserProvider implements UserProviderInterface{ public function loadUserByUsername($username) { // "load" the user - e.g. load from the db $user = new User(); $user->setUsername($username); return $user; } public function refreshUser(UserInterface $user) { return $user; } public function supportsClass($class) { return $class == 'AppBundle\Entity\User'; }}

But why!?

Page 50: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

class SunnyUserProvider implements UserProviderInterface{ public function loadUserByUsername($username) { // "load" the user - e.g. load from the db $user = new User(); $user->setUsername($username); return $user; } public function refreshUser(UserInterface $user) { return $user; } public function supportsClass($class) { return $class == 'AppBundle\Entity\User'; }}

refresh from the session

Page 51: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

class SunnyUserProvider implements UserProviderInterface{ public function loadUserByUsername($username) { // "load" the user - e.g. load from the db $user = new User(); $user->setUsername($username); return $user; } public function refreshUser(UserInterface $user) { return $user; } public function supportsClass($class) { return $class == 'AppBundle\Entity\User'; }}

switch_user, remember_me

Page 52: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Slightly more sunshiney:

Loading a User from the Database

@weaverryan

Page 53: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function getUser($credentials, UserProviderInterface $userProvider) { $username = $credentials['username']; //return $userProvider->loadUserByUsername($username); return $this->em ->getRepository('AppBundle:User') ->findOneBy(['username' => $username]);}

FormLoginAuthenticator

you can use this if you want to… or don’t!

Page 54: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

class SunnyUserProvider implements UserProviderInterface{ public function loadUserByUsername($username) { $user = $this->em->getRepository('AppBundle:User') ->findOneBy(['username' => $username]); if (!$user) { throw new UsernameNotFoundException(); } return $user; } }

@weaverryan

(of course, the “entity” user provider does this automatically)

Page 55: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Easiest Example ever:

Api (JWT) Authentication

@weaverryan

Warmest

Page 56: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

JSON Web Tokens

@weaverryan

Q) What if an API client could simply send you its user id as authentication?

Authorization: Bearer 123

Page 57: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

1) API client authenticates

" API client

Hey dude, I’m weaverryan

POST /token username=weaverryan

password=I<3php

#

app

Page 58: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

2) Is this really weaverryan?

" API client

“It checks out, weaverryan’s password really is I<3php. Nerd”

POST /token username=weaverryan

password=I<3php

#

app

Page 59: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

3) Create a package of data

" API client

#

app

$data = [ 'username' => 'weaverryan'];

Page 60: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

4) Sign the data!$data = [ 'username' => 'weaverryan']; // package: namshi/jose$jws = new SimpleJWS(['alg' => 'RS256']);$jws->setPayload($data); $privateKey = openssl_pkey_get_private( 'file://path/to/private.key' ); $jws->sign($privateKey); $token = $jws->getTokenString()

Page 61: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

5) Send the token back!

" API client

#

app{ "token": "big_long_json_webtoken"}

POST /token username=weaverryan

password=I<3php

Page 62: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

6) Client sends the token

" API client

#

app

GET /secret/stuff Authorization: Bearer big_login_json_webtoken

Page 63: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

7) Verify the signature

// "Authorization: Bearer 123" -> "123"$authHeader = $request->headers->get('Authorization');$headerParts = explode(' ', $authHeader);$token = $headerParts[1]; $jws = SimpleJWS::load($token);$public_key = openssl_pkey_get_public( '/path/to/public.key'); if (!$jws->isValid($public_key, 'RS256')) { die('go away >:(') }

Page 64: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

8) Decode the token

$payload = $jws->getPayload();$username = $payload['username'];

Page 65: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

How in Symfony?

@weaverryan

Page 66: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

@weaverryan

1) Install a library to help sign tokens

composer require lexik/jwt-authentication-bundle

Page 67: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

@weaverryan

2) Create a public & private key

mkdir var/jwt

openssl genrsa -out var/jwt/private.pem 4096

openssl rsa -pubout -in var/jwt/private.pem \ -out var/jwt/public.pem

Page 68: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

@weaverryan

3) Point the library at them

# app/config/config.ymllexik_jwt_authentication: private_key_path: %kernel.root_dir%/../var/jwt/private.pem public_key_path: %kernel.root_dir%/../var/jwt/public.pem

Page 69: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

4) Endpoint to return tokens/** * @Route("/token") */public function fetchToken(Request $request) { $username = $request->request->get('username'); $password = $request->request->get('password'); $user = $this->getDoctrine() ->getRepository('AppBundle:User') ->findOneBy(['username' => $username]); if (!$user) { throw $this->createNotFoundException(); } // check password $token = $this->get('lexik_jwt_authentication.encoder') ->encode(['username' => $user->getUsername()]); return new JsonResponse(['token' => $token]);}

Page 70: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

5) Create the JWT Authenticator

Page 71: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

class JwtAuthenticator extends AbstractGuardAuthenticator{ private $em; private $jwtEncoder; public function __construct(EntityManager $em, JWTEncoder $jwtEncoder) { $this->em = $em; $this->jwtEncoder = $jwtEncoder; } public function getCredentials(Request $request) { } public function getUser($credentials, UserProviderInterface $userProvider) { } public function checkCredentials($credentials, UserInterface $user) { } public function onAuthenticationFailure(Request $request) { } public function onAuthenticationSuccess(Request $request, TokenInterface $token) { } // …}

Page 72: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function getCredentials(Request $request) { $extractor = new AuthorizationHeaderTokenExtractor( 'Bearer', 'Authorization' ); $token = $extractor->extract($request); if (false === $token) { return; } return $token; }@weaverryan

Page 73: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function getUser($credentials, UserProviderInterface $userProvider) { $data = $this->jwtEncoder->decode($credentials); if (!$data) { return; } $username = $data['username']; return $this->em ->getRepository('AppBundle:User') ->findOneBy(['username' => $username]);}

@weaverryan

Page 74: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function checkCredentials($credentials, UserInterface $user) { // no credentials to check return true; }

@weaverryan

Page 75: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function onAuthenticationFailure(Request $request, AuthenticationException $exception) { return new JsonResponse([ 'message' => $exception->getMessageKey() ], 401); }

@weaverryan

Page 76: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) { // let the request continue to the controller return; }

@weaverryan

Page 77: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Register as a service

# app/config/services.ymlservices: jwt_authenticator: class: AppBundle\Security\JwtAuthenticator autowire: true

@weaverryan

Page 78: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Activate in your firewallsecurity: # ... firewalls: main: # ... guard: authenticators: - form_login_authenticator - jwt_authenticator entry_point: form_login_authenticator

which “start” method should be called

Page 79: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

curl http://localhost:8000/secure

<!DOCTYPE html><html> <head> <meta charset="UTF-8" /> <meta http-equiv="refresh" content="1;url=/login" />

<title>Redirecting to /login</title> </head> <body> Redirecting to <a href="/login">/login</a>. </body></html>

@weaverryan

Page 80: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

curl \--header “Authorization: Bearer BAD" \http://localhost:8000/secure

{"message":"Username could not be found."}

@weaverryan

Page 81: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

curl \--header “Authorization: Bearer GOOD" \http://localhost:8000/secure

{"message":"Hello from the secureAction!"}

@weaverryan

Page 82: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Social Login!

@weaverryan

Page 83: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

$

AUTHENTICATOR

/facebook/check?code=abc

give me user info!

load a User object

" User

$

Page 84: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

composer require \ league/oauth2-facebook \ knpuniversity/oauth2-client-bundle

@weaverryan

Page 85: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

@weaverryan

# app/config/config.ymlknpu_oauth2_client: clients: # creates service: "knpu.oauth2.client.facebook" facebook: type: facebook client_id: %facebook_client_id% client_secret: %facebook_client_secret% redirect_route: connect_facebook_check graph_api_version: v2.5

Page 86: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

@weaverryan

/** * @Route("/connect/facebook", name="connect_facebook") */public function connectFacebookAction() { return $this->get('knpu.oauth2.client.facebook') ->redirect(['public_profile', 'email']);}

/** * @Route("/connect/facebook-check", name="connect_facebook_check") */public function connectFacebookActionCheck() { // will not be reached!}

Page 87: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

class FacebookAuthenticator extends AbstractGuardAuthenticator{ public function getCredentials(Request $request) { } public function getUser($credentials, UserProviderInterface $userProvider) { } public function checkCredentials($credentials, UserInterface $user) { } public function onAuthenticationFailure(Request $request) { } public function onAuthenticationSuccess(Request $request, TokenInterface $token) { } public function start(Request $request, AuthenticationException $e = null) { } public function supportsRememberMe() { }}

Page 88: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function getCredentials(Request $request) { if ($request->getPathInfo() != '/connect/facebook-check') { return; } return $this->oAuth2Client->getAccessToken($request); }

@weaverryan

Page 89: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function getUser($credentials, …) { /** @var AccessToken $accessToken */ $accessToken = $credentials; /** @var FacebookUser $facebookUser */ $facebookUser = $this->oAuth2Client ->fetchUserFromToken($accessToken); // ...}

@weaverryan

Page 90: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Now, relax in the shade!

@weaverryan

Page 91: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

@weaverryan

public function getUser($credentials, ...){ // ... /** @var FacebookUser $facebookUser */ $facebookUser = $this->oAuth2Client ->fetchUserFromToken($accessToken); // 1) have they logged in with Facebook before? Easy! $user = $this->em->getRepository('AppBundle:User') ->findOneBy(array('email' => $facebookUser->getEmail())); if ($user) { return $user; } // ...}

Page 92: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function getUser($credentials, ...){ // ... // 2) no user? Perhaps you just want to create one // (or redirect to a registration) $user = new User(); $user->setUsername($facebookUser->getName()); $user->setEmail($facebookUser->getEmail()); $em->persist($user); $em->flush();

return $user; }

@weaverryan

Page 93: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function checkCredentials($credentials, UserInterface $user) { // nothing to do here!} public function onAuthenticationFailure(Request $request ...){ // redirect to login} public function onAuthenticationSuccess(Request $request ...){ // redirect to homepage / last page}

@weaverryan

Page 94: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

* also supports “finishing registration”

@weaverryan

Page 95: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Extra Sunshine(no sunburn)

@weaverryan

Page 96: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Can I control the error message?

@weaverryan

Page 97: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

@weaverryan

If authentication failed, it is becausean AuthenticationException(or sub-class) was thrown

(This has nothing to do with Guard)

Page 98: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function onAuthenticationFailure(Request $request, AuthenticationException $exception) { return new JsonResponse([ 'message' => $exception->getMessageKey() ], 401); }

@weaverryan

Beach Vacation Bonus! The exception is passedwhen authentication fails

AuthenticationException has a hardcodedgetMessageKey() “safe” string

Invalid credentials.

Page 99: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function getCredentials(Request $request) { } public function getUser($credentials, UserProviderInterface $userProvider) { } public function checkCredentials($credentials, UserInterface $user) { }

Throw an AuthenticationException at anytime in these 3 methods

Page 100: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

How can I customize the message?

@weaverryan

Create a new sub-class of AuthenticationException for each message

and override getMessageKey()

Page 101: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

CustomUserMessageAuthenticationException

@weaverryan

Page 102: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function getUser($credentials, ...){ $apiToken = $credentials; $user = $this->em ->getRepository('AppBundle:User') ->findOneBy(['apiToken' => $apiToken]); if (!$user) { throw new CustomUserMessageAuthenticationException( 'That API token is stormy' ); } return $user; }

@weaverryan

Page 103: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

I need to manually authenticate my user

@weaverryan

Page 104: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

public function registerAction(Request $request) { $user = new User(); $form = // ... if ($form->isValid()) { // save the user $guardHandler = $this->container ->get('security.authentication.guard_handler'); $guardHandler->authenticateUserAndHandleSuccess( $user, $request, $this->get('form_login_authenticator'), 'main' // the name of your firewall ); // redirect } // ...}

Page 105: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

I want to save a lastLoggedInAt

field on my user no matter *how* they login

@weaverryan

Page 106: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Chill… that was already possible

SecurityEvents::INTERACTIVE_LOGIN

@weaverryan

Page 107: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

class LastLoginSubscriber implements EventSubscriberInterface{ public function onInteractiveLogin(InteractiveLoginEvent $event) { /** @var User $user */ $user = $event->getAuthenticationToken()->getUser(); $user->setLastLoginTime(new \DateTime()); $this->em->persist($user); $this->em->flush($user); } public static function getSubscribedEvents() { return [ SecurityEvents::INTERACTIVE_LOGIN => 'onInteractiveLogin' ]; }}

@weaverryan

Page 108: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

@weaverryan

Ok, so how do I make my weird auth system?

Page 109: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

1. User implements UserInterface

@weaverryan

Page 110: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

2. UserProvider

@weaverryan

Page 111: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

3. Create your authenticator(s)

@weaverryan

Page 112: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

Authentication%

@weaverryan

Page 113: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

@weaverryan

Do it:

http://symfony.com/doc/current/cookbook/security/guard-authentication.html

http://KnpUniversity.com/guard

Page 114: Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

@weaverryan

New (free) Symfony 3 Tutorial

KnpUniversity.com

Thank You!