WEBVTT NOTE Created by CaptionSync from Automatic Sync Technologies www.automaticsync.com 00:00:01.086 --> 00:00:04.376 align:middle We just found out that, if we send a bad email & password 00:00:04.376 --> 00:00:10.556 align:middle to the built-in json_login authenticator, it sends back a nicely-formed JSON response: 00:00:11.166 --> 00:00:13.476 align:middle an error key set to what went wrong. 00:00:14.226 --> 00:00:16.626 align:middle Great! We can totally work with that! 00:00:17.196 --> 00:00:24.376 align:middle But, if you do need more control, you can put a key under json_login called failure_handler. 00:00:24.796 --> 00:00:29.246 align:middle Create a class, make it implement AuthenticationFailureHandlerInterface, 00:00:29.476 --> 00:00:31.226 align:middle then use that class name here. 00:00:31.896 --> 00:00:34.006 align:middle With that, you'll have full control 00:00:34.006 --> 00:00:37.836 align:middle to return whatever response you want on authentication failure. 00:00:38.506 --> 00:00:39.436 align:middle But this is good! 00:00:39.866 --> 00:00:42.076 align:middle Let's use this to show the error on the frontend. 00:00:42.076 --> 00:00:49.216 align:middle If you're familiar with Vue.js, I have a data key called error which, 00:00:49.446 --> 00:00:53.296 align:middle up here on the login form, I use to display an error message. 00:00:53.936 --> 00:01:00.346 align:middle In other words, all we need to do is set this.error to a message and we're in business! 00:01:01.116 --> 00:01:01.686 align:middle Let's do that! 00:01:01.686 --> 00:01:10.856 align:middle First, if error.response.data, then this.error = error.response.data.error. 00:01:11.786 --> 00:01:19.026 align:middle Ah, actually, I messed up here: I should be checking for error.response.data.error - 00:01:19.236 --> 00:01:22.706 align:middle I should be checking to make sure the response data has that key. 00:01:23.256 --> 00:01:26.166 align:middle And, I should be printing just that key. 00:01:26.796 --> 00:01:29.386 align:middle I'll catch half of my mistake in a minute. 00:01:30.126 --> 00:01:36.856 align:middle Anyways, if we don't see an error key, something weird happened: set the error to Unknown error. 00:01:38.356 --> 00:01:40.286 align:middle Move over, refresh... 00:01:41.096 --> 00:01:43.366 align:middle and let's fail login again. 00:01:45.356 --> 00:01:48.376 align:middle Doh! It's printing the entire JSON message. 00:01:48.796 --> 00:01:51.346 align:middle Now I'll add the missing .error key. 00:01:51.906 --> 00:01:54.886 align:middle But I should also include it on the if statement above. 00:01:56.756 --> 00:01:57.666 align:middle Try it again... 00:01:59.356 --> 00:02:00.886 align:middle when we fail login... 00:02:01.356 --> 00:02:02.796 align:middle that's perfect! 00:02:04.096 --> 00:02:07.966 align:middle But there's one other way we could fail login that we're not handling. 00:02:08.756 --> 00:02:10.796 align:middle Axios is smart... 00:02:10.796 --> 00:02:12.786 align:middle or at least, it's modern. 00:02:13.566 --> 00:02:20.636 align:middle We pass it these two fields - email and password - and it turned that into a JSON string. 00:02:21.396 --> 00:02:23.036 align:middle You can see this in our network tab... 00:02:24.406 --> 00:02:25.326 align:middle down here... 00:02:25.786 --> 00:02:32.556 align:middle Axios set the Content-Type header to application/json and turned the body into JSON. 00:02:33.536 --> 00:02:35.956 align:middle Most AJAX clients don't do this. 00:02:36.546 --> 00:02:41.536 align:middle Instead, they send the data in a different format that matches what happens 00:02:41.536 --> 00:02:44.496 align:middle when you submit a traditional HTML form. 00:02:45.536 --> 00:02:51.166 align:middle If our AJAX client had done that, what do you think the json_login authenticator would 00:02:51.166 --> 00:02:51.706 align:middle have done? 00:02:52.196 --> 00:02:54.786 align:middle An error? Let's find out! 00:02:55.696 --> 00:02:59.826 align:middle Temporarily, I'm going to add a third argument to .post(). 00:03:00.636 --> 00:03:07.116 align:middle This is an options array and we can use a headers key to set the Content-Type header 00:03:07.116 --> 00:03:12.216 align:middle to application/x-www-form-urlencoded. 00:03:13.176 --> 00:03:16.786 align:middle That's the Content-Type header your browser sends when you submit a form. 00:03:17.466 --> 00:03:24.806 align:middle This will tell Axios not to send JSON: it will send the data in a format that's invalid 00:03:24.996 --> 00:03:27.486 align:middle for the json_login authenticator. 00:03:28.596 --> 00:03:29.926 align:middle Go refresh the Javascript... 00:03:30.176 --> 00:03:32.446 align:middle and fill out the form again. 00:03:33.396 --> 00:03:35.966 align:middle I'm expecting that we'll get some sort of error. 00:03:37.266 --> 00:03:38.546 align:middle Submit and... 00:03:38.926 --> 00:03:41.996 align:middle huh. A 200 status code? 00:03:41.996 --> 00:03:47.266 align:middle And the response says user: null. 00:03:48.336 --> 00:03:50.646 align:middle This is coming from our SecurityController! 00:03:51.456 --> 00:03:55.606 align:middle Instead of intercepting the request and then throwing an error 00:03:55.606 --> 00:03:57.646 align:middle when it saw the malformed data... 00:03:58.016 --> 00:04:00.486 align:middle json_login did nothing! 00:04:01.316 --> 00:04:06.326 align:middle It turns out, the json_login authenticator only does its work 00:04:06.406 --> 00:04:09.706 align:middle if the Content-Type header contains the word json. 00:04:09.706 --> 00:04:15.716 align:middle If you make a request without that, json_login does nothing and we end 00:04:15.716 --> 00:04:17.526 align:middle up here in SecurityController.... 00:04:17.866 --> 00:04:20.256 align:middle which is probably not what we want. 00:04:20.966 --> 00:04:25.486 align:middle We probably want to return a response that tells the user what they messed up. 00:04:25.486 --> 00:04:27.216 align:middle Simple enough! 00:04:27.216 --> 00:04:31.686 align:middle Inside of the login() controller, we now know that there are two situations 00:04:31.686 --> 00:04:38.416 align:middle when we'll get here: either we hit json_login and were successfully authenticated - 00:04:38.896 --> 00:04:43.476 align:middle we'll see that soon - or we sent an invalid request. 00:04:44.166 --> 00:04:49.616 align:middle Cool: if !$this->isGranted('IS_AUTHENTICATED_FULLY') - 00:04:49.926 --> 00:04:57.416 align:middle so if they're not logged in - return $this->json() and follow the same error format 00:04:57.416 --> 00:05:03.906 align:middle that json_login uses: an error key set to: Invalid login request: 00:05:04.596 --> 00:05:08.086 align:middle check that the Content-Type header is "application/json". 00:05:10.956 --> 00:05:14.206 align:middle And set this to a 400 status code. 00:05:14.206 --> 00:05:15.666 align:middle I love it! 00:05:15.666 --> 00:05:16.756 align:middle Let's make sure it works. 00:05:17.766 --> 00:05:21.106 align:middle We didn't change any JavaScript, so no refresh needed. 00:05:21.826 --> 00:05:23.176 align:middle Submit and... 00:05:23.386 --> 00:05:24.366 align:middle we got it! 00:05:25.036 --> 00:05:28.726 align:middle The "error" side of our login is bulletproof. 00:05:28.796 --> 00:05:30.796 align:middle Head back to our JavaScript and... 00:05:30.796 --> 00:05:34.456 align:middle I guess we should remove that extra header so things work again. 00:05:40.046 --> 00:05:43.506 align:middle Now... we're back to "Invalid credentials". 00:05:44.586 --> 00:05:48.716 align:middle Next... I think we should try putting in some valid credentials! 00:05:49.076 --> 00:05:54.276 align:middle We'll hack a user into our database to do this and talk about our session-based authentication.