Sanctum SPA Overview0:00
Okay, let's take a look at Laravel's Sanctum. It provides a lightweight auth system for single-page apps, or token-based auth for other clients such as mobile apps. In this video, we'll take a look at the auth system for single-page apps. For this, Sanctum uses Laravel's built-in cookie authentication, providing us with CSRF protection and protection against cross-site scripting. So we're going to be working with two projects here, a backend app using Laravel and Sanctum, and a fairly bare-bones frontend app that is built using Vue CLI. In the process, you'll see the entire workflow from setting cookies and making subsequent requests to protected routes.
In the process, you'll see the entire workflow from setting cookies and making subsequent requests to protected routes. Note that for this to work, our frontend and our backend have to be running on the same domain. In this demo, they'll be running on the localhost domain, but in production, you might have, say, the frontend running on the top-level domain and the backend running on a subdomain. And you can configure that using environment variables, which I will show you here. Okay, so let's start with the backend. So I'm going to start from scratch here. Let's make a new project called Laravel-New-Sanctum-Example.
Backend Setup and Install1:04
So I'm going to start from scratch here. Let's make a new project called Laravel-New-Sanctum-Example. And let's go ahead and go into that. Okay. And let's go ahead and use Composer to install Sanctum. I'm also going to install the Laravel UI package because that has the routes for the auth scaffolding, which we can make use of, so Laravel UI. Okay. And let's make sure the auth scaffolding is in place, so php artisan ui vue, or you can use just bootstrap and make sure to pass in --auth.
And let's make sure the auth scaffolding is in place, so php artisan ui vue, or you can use just bootstrap and make sure to pass in --auth. And that should be good. Okay. Now let's publish the Sanctum config. So let's go ahead and do this. Okay. And there's also migrations here, which is mostly for the token auth, but we'll migrate it anyways. So I already have a database set up.
it anyways. So I already have a database set up. Let me just, so let me go into my .env file and set up my database. It's just the same name as the project, so Sanctum-Example. And let's go ahead and migrate, php artisan migrate. Okay. Now it says to add this middleware here. So ensure front-end requests are stateful in our app/Http/Kernel.php, so let's do that. Copy that. Go into our app/Http/Kernel.php.
Copy that. Go into our app/Http/Kernel.php. And let's paste that here. And let's grab this and put it in our api middleware. So that should be down here. Okay. What's next? So if you want to ignore the migrations, you can do that as well, but we'll just leave it. And now this is for the API token stuff, which we're not going to look at.
Configure Domains and CORS2:46
it. And now this is for the API token stuff, which we're not going to look at. So let's scroll down to SPA authentication. So the first step is to configure your first party domains. So it says right here, you should configure which domains your SPA will be making requests from. So this is basically where your front-end lives. So if you go into the config, so config/sanctum.php, you'll see a stateful key here. And the default is localhost and 127.0.0.1. And you can also comma separate it if you want.
And in our case, we can just do what the default is. So these two, localhost and 127.0.0.1. Okay. Okay, now the middleware we did already. Okay, now we have to set up CORS. And in Laravel 7, the fruitcake/laravel-cors package comes baked into the framework. So you'll see a config here, and we have to change some stuff here too. So we have to add supports_credentials here, so set that to true. And we also have to set up the paths where we want cross-origin to be available. So right now, by default, there's the api/whatever route, but we also have to
And we also have to set up the paths where we want cross-origin to be available. So right now, by default, there's the api/{any} route, but we also have to add the login route, which we're going to be making use of to log in, the logout route, and also the sanctum/csrf-token route. Is it token or cookie? It's cookie. So this route right here. And you'll see what this is in a second, once we go to our front-end. Okay. And after that, it says to make sure you have withCredentials set on axios.
Okay. And after that, it says to make sure you have withCredentials set on axios. And we'll do this in the front-end. And now it says, make sure to set the domain key in your session config to the domain your app lives on. So in our case, let me just show you that actually. So config/session.php. So by default, where's domain here? Right here, it's null by default. We want to set this in our .env file.
Right here, it's null by default. We want to set this in our .env file. Let's put it right here. And this is the domain where your app lives. And if you're supporting subdomains, you want to put a dot before the domain. In our case, it's just localhost. But if you were to put this to production, you would say dot slash laracasts.com or something. Okay, so let's put this to localhost. So that should be all the config for our back-end. And usually I would make use of something like Laravel Valet and just use the dot test.
So that should be all the config for our back-end. And usually I would make use of something like Laravel Valet and just use the .test domain to test out the application. But in our case, like I said, we have to be on the localhost domain. So I'm going to do good old php artisan serve. And now our app is running in this 127.0.0.1, which is also an alias for localhost. And that should work too. So I'm going to make a User here just so we can play around in the front end with it. So User, say Andre, user@example.com and password, okay. So there should be a User in our database now.
Create Vue Frontend App6:32
So User, say Andre, user at user.com and password, password, okay. So there should be a User in our database now. And we can use this to test this out in our front end. Okay, now let's create the front end. And I'm going to go ahead and view, create, view Sanctum example. And let me go ahead and manually select features. And I'm going to turn off the limiter just so it doesn't annoy us. And I'm also going to add the router here, okay. That's fine, fine. No.
That's fine, fine. No. Okay, that's done. Let's go ahead and go into it. And I'm also going to install Axios here. So npm install Axios. Okay, I'm going to open up in VS Code, and I'm going to run npm run serve. Okay, now our app is running on localhost as well, but on a different port. So now we have both our apps on the localhost domain, okay. So we're going to use the home route for our login view.
So now we have both our apps on the localhost domain, okay. So we're going to use the home route for our login view. So let's quickly scaffold that out. So that would be in source, views, home. Let me just get rid of all of this. So image, say loginForm, don't need this, don't need components, okay. And I'm going to make one more route here or one more view for the dashboard, and I'm just going to duplicate it from the about page, duplicate dashboard view. And this view is just the logged in view once the user logs in. So let's say dashboard and say dashboard view, view, sorry.
And this view is just the logged in view once the User logs in. So let's say dashboard and say dashboard view, view, sorry. And let's add that to these links up here, which is, I believe, in app/View right here. So yeah, there's one more here. Let's add a pipe here, and let's add dashboard, dashboard. And obviously, we have to add this to our routes, which is in the router/index. And I'm just going to copy this one and paste it here, and say /dashboard. Name is going to be dashboard, and the component is dashboard, okay. And make sure to import that up here. So dashboard.
And make sure to import that up here. So dashboard. And if I did that right, everything should work. There we go, cool. Okay, let's continue. I am going to paste some code in for a very ugly form, which will serve as our login form. Sorry, let me just paste the whole thing in. Okay, and it's very bare bones, just a form with two inputs, email and password. And we have a submit prevent, and that calls a login method, which we will create right now.
And we have a submit prevent, and that calls a login method, which we will create right now. So let's create methods, login, and it's just console.log, logging in, see if it works. And let's open up DevTools. And as you see, I have the application tab opened with cookies here, and these are from a previous project. So let me delete these. So open up the console and press login, and there you see login, okay. So let's go ahead and import Axios, and let's add this, defaults with credentials. So let's do that.
So let's go ahead and import Axios, and let's add this, defaults with credentials. So let's do that. So import Axios from Axios. Let's paste that in. And I want to set one more default, so axios.defaults. And that's going to be the base URL. And usually you would store this in an .env file, but for this time, I'll just put it here. So localhost:8000 is our backend. And for now, let's just hard code our credentials in.
Implement Login with CSRF10:49
So localhost:8000 is our backend. And for now, let's just hard code our credentials in. So I showed you earlier, I made a User, so let's try that User. So if you look at the documentation, it says right here, to authenticate your SPA, you should first make a request to this endpoint. And this will initialize the CSRF cookie, which we need. So the CSRF protection is in place. So let's go ahead and grab this, and paste it in here. And let's just console.log the response and see if we get anything. And I'm going to open the application tab and see if any cookies appear in here, once
Okay, there's none, console, login, okay. And you see this 204, no content, but this should have set some cookies in our application. And there we go. We see the CSRF token cookie, and we see a session cookie here. So now at this point, we are able to make requests to the login endpoint. So if you go here, it says, once CSRF protection has been initialized, you can make a POST request to the login route, which we have in place because we installed the Laravel UI package. So let's go ahead and do that. So in here, we don't need this anymore.
So let's go ahead and do that. So in here, we don't need this anymore. Actually, let me just delete it, we want to make another request, we just move this up. And the login route is a POST route, and say /login. And we also want to pass in some data. And we want to pass in the email. And it's going to hard code it for now. This will obviously come from the form. And password, password. And let's go ahead and do a dd().
And we're getting a 422. So let's see what that is. So here it is. Okay, it says credentials do not match our records. So we are successfully communicating with the server, but for some reason, my credentials are not correct. Oh, sorry. If you look at my database, I actually named the user user at user.com. So let's try this again. I'm going to go to my application, let's delete the cookies to make sure.
So let's try this again. I'm going to go to my application, let's delete the cookies to make sure. Let's change our application to user at user.com. Okay, this should refresh, go back to console, let's clear this, and let's try again. There we go. So now we get 204 again, but if you check our cookies, so application, cookies, again, you see the same thing, the CSRF token and the session. But now we should be authenticated. So since we're authenticated, that means our cookies should be valid. So here's what I'm going to do, I'm going to the dashboard view, and I'm going to want
Protect Routes and Logout14:22
So since we're authenticated, that means our cookies should be valid. So here's what I'm going to do, I'm going to the dashboard view, and I'm going to want to hit a protected route here. So if we go into our backend, so back to Sublime, if you go into routes/api, I just want to hit this endpoint and get information about the logged in user. So we have to change this middleware to Auth::sanctum, instead of Auth::api. And that should work if I did everything correctly. And now in our dashboard, let's go ahead and make a request to that endpoint. So I'm just going to grab that. Actually, I have to grab all this as well.
So I'm just going to grab that. Actually, I have to grab all this as well. So this is duplicated, but that's okay for this demo, script, export default. Let's put that there. And let me grab that again. The Axios call, okay, dashboard, go in here. Sorry, this should be in a mounted hook. So mounted or created, doesn't matter. And that endpoint is API user. So let's try that.
And that endpoint is API User. So let's try that. And let's just console.log the response, see if we're getting the logged in User back. And if we are, that means everything is correct and working. So back to our console, our cookies should be set and refresh. And there we go. If we see the data here, you'll see the information about the logged in User. So let's go ahead and just dump that information right here underneath the dashboard view. So just say div email is going to be email, and we'll make a piece of state for that right here.
So just say div email is going to be email, and we'll make a piece of state for that right here. So data, return object, email, make it empty. And then let's set it in here. So this.email is response, oops, response.data.email. And let's see if this works. Cool. Okay, so I want to change the login route here. So when it's successful in here, I just want to redirect to the dashboard. So we can do that with view router doing this router.push.
So when it's successful in here, I just want to redirect to the dashboard. So we can do that with view router doing this router.push. And you can just push to the actual route. Or for me personally, I like using named routes, both in Laravel and in Vue. So I do name dashboard, because that's what we named it in a route file. So I'm going to save this and try actually before I save it, let me just start from scratch, remove all the tokens, I mean, all the cookies, go back home. And I'll save it. Okay, and now let's try this again. So now it should redirect to the dashboard.
Okay, and now let's try this again. So now it should redirect to the dashboard. Once we log in. So let me just refresh and see if this works. And there we go. It does work. Awesome. Okay, let's add the logout functionality. And again, we're just going to make use of the built in logout function in Laravel, or in the auth scaffolding.
And again, we're just going to make use of the built in logout function in Laravel, or in the auth scaffolding. So let's go ahead and quickly do that. Back to our dashboard. Let's add a new button down here underneath the email for logging out. So logout and say, add click equals logout. And let's make a method for that underneath here. So methods, logout. And all we're going to do is post to the logout route. So axios.post('/logout') and response.
And all we're going to do is post to the logout route. So axios.post /logout and response. And I'm going to do the same thing here and redirect back to the login page if it's successful. So this router.push and name is home. So hopefully this works. So let's open the network tab and see if we get a successful response when we log out. So let me just refresh and log out. And 204 is successful. And we are redirected back to our login screen. Awesome.
