Authentication with Laravel Sanctum
Tags: laravel, sanctum, authentication, tokens
Published: 2021-06-20 18:11:18

This entire week at work was spent messing around with Nativescript, specifically the Vue flavor with typescript, ionic, and react native thrown in there.  It was rather frustrating even just getting the different environments getting up and running locally.  I've always known that it takes a special kind of person to be a mobile engineer and this week proved it to me.  And then forget all these "dual" languages if you're a true native engineer then I just have to say you're a better person than me.   So we as a company have decided with our current staff and the fact that we want a very simple app to interact with our API, Nativescript-vue hits all of the marks for us.  

I'll definitely be going a lot further in detail about this project and we'll have a week by week recap of me trying to build this app.  But this week was a lot of roadblocks but one thing that is a constant is no matter what language we use we are going to need it to interact with our API and we need some way of authentication in place.  Why Sanctum?  Well for our needs it seems passport would be a bit overkill and yes we could've done JWT / Firebase authentication, or you can build a custom auth setup in house.  All are valid options but we decided on the small foot print of Sanctum.  If you've ever installed Passport it's super similar and you shouldn't have any issues.  For anyone who's never done auth this post is for you.  There are a few steps that the docs forget to mention but if you've set something up before you'll remember real quick when a few errors present themselves.  

And on to the [Sanctum](https://laravel.com/docs/8.x/sanctum) docs.  Follow the install steps with a simple `composer require laravel/sanctum`  
`php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"` to publish the config files and last but not least: `php artisan migrate` and migrate the new Sanctum tables.  Generally speaking you'll be using the trait on the `User` model and bring in the namespace `use Laravel\Sanctum\HasApiTokens;` and make sure to add the Trait `use HasApiTokens`.  

So we are pretty much set up and now just have to create a route / controller, and to do a few more little nicks and nacks to get everything up and running properly.  So in the `web.php` file (yours might be different just depends on how you have your routing set up.  I decided to use the route `/tokens/create` and I point it to a newly created `AuthController@login`.  I debated on what to call the function in the newly created controller (I didn't use the cli just created the file and copied / pasted one of my other controller and fixed namespaces.  Call the route / function whatever you want it really is up to you.  Leave a funny easter egg?  Go for it , I know I could 100% cause of the small size of the team but I chose the traditional route lol. If you try to hit this route now you'll get a 419 (page expired route), but why?  Well since it's in the web file all web middleware is present and what's not present in postman / a browser right now is: CSRF token.  So we need to open up `VerifyCsrfToken.php` and add our recently created route, in my case `/tokens/create` in except array so that CSRF token is not checked for.   

So in my login function I need to check an email / password against DB values.  If they are indeed correct I return a token, if not return them to HELL!!!!!!!!!  No but for real.  Normally on a web app it would redirect to login but this is all for a mobile application and I'm not 100% sure of the flow for that scenario.  I'll cross that bridge in the next couple of weeks and you can bet there will be talk about it all here.  
```
    public function login(Request $request)
    {
        $user = User::where('email', $request->email)->first();

        if (! $user || ! Hash::check($request->password, $user->password)) {
            throw ValidationException::withMessages([
                'email' => ['The provided credentials are incorrect.'],
            ]);
        }

        return $user->createToken($request->device_name)->plainTextToken;
    }
```
So this is the route I went, you can use `Auth::attempt` which takes in an email/password and returns a boolean this is just the particular way that I went.  So first off the email passed in is not in our DB it throws and exception and returns an error message.  Same if the passed in password and the stored password (using the Hash facade, cause remember we can't just check them regularly) for the now user (by the passed in email) do not match.  So if all is good we return the token.  Now eventually I'm gonna make this all into a nice API resource but for now we are just making sure that the basics are installed.     So hit the route in POSTMAN with an email / password that you know works and you should get something like this in return: `5|eOMh3OFK4u21rx6Ggqj4QXCzSQnwvO0lpB47baK1` and if the creds don't match you get our home page returned.  Again I need to customize all of this but for now I want to make sure with proper creds we get a token then hit a route with that token and make sure it's good.  

```
Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});
```
This a great way to test the token and it's the first route in my `api.php` file and again this may be different depending on how your routes are setup.  So now we have one more thing to take care of and it's to set the API driver to 'sanctum' and this can be found in the `auth.php` config file.  Then generally we'd set the provider to `users` since that is where I added the trait `HasApiTokens`.  

Last things last I add my newly created token in the Auth Headers as a Bearer Token in postman and use the route to check if my token is valid.  `/api/user` and if the token is valid it should return the user whom the token was created for.  If the token is invalid then you'll get the login page returned.  Again I need to figure out the flow of things but I can verify that in fact my new authentication system is in fact working.  One thing to make sure is anytime you make a change to a config file you'll need to run `php artisan config:cache` or `php artisan config:clear` so those new config values are cached.  So that's really it for this week and again if you've every set up passport or any other type of JWT authentication system for laravel this was probably one of the worst things you've read in who knows how long, so for that I apologize, but I warned you at first and now that apology has been revoked.  Till next week...