DEV Community

Cover image for Authenticating a React App with Laravel Sanctum - Part 1
Dog Smile Factory
Dog Smile Factory

Posted on • Updated on • Originally published at

Authenticating a React App with Laravel Sanctum - Part 1

My tech stack of choice for building web applications is React on the front end and Laravel on the back. One of the challenges of this approach involves authenticating the user so that database resources are only available to authorized individuals. This task is a lot more straightforward now that the Sanctum package has been added to Laravel 7.

To show how this works, I've created a simple application made up of three parts

  • the user signs up for access
  • the user logs in
  • the user logs out

You can try it out here and view the complete code for the React client application and the Laravel server application.

Laravel with Sanctum

Laravel Sanctum handles all the work of authenticating your users. However, there are a lot of little details to get this set up. Just take them one at a time, don't miss any steps, and you'll have your application working perfectly in very short order.

This guide assumes that you have a basic familiarity with setting up and running a Laravel application, including using the command line and running Laravel artisan commands.


First, you're going to need a database for saving your information. I used MySQL for this application and created a database named auth.

Install Laravel

Then I created my Laravel app, using Composer:

composer create-project --prefer-dist laravel/laravel APP_NAME

There are detailed instructions for starting a new project on the Laravel site.

Edit the .env file to update the application name and your database information.




Install and Configure Sanctum

CD into the application directory and add Sanctum to the project.

composer require laravel/sanctum

Next, create a Sanctum configuration file and the database tables.

php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

php artisan migrate

Update app/Http/Kernel.php to add the Sanctum middleware to the API middleware group.

Add the following lines of code:

use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;


'api' => [

as shown below:


namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;

class Kernel extends HttpKernel
     * The application's global HTTP middleware stack.
     * These middleware are run during every request to your application.
     * @var array
    protected $middleware = [

     * The application's route middleware groups.
     * @var array
    protected $middlewareGroups = [
        'web' => [
            // \Illuminate\Session\Middleware\AuthenticateSession::class,

        'api' => [

Configure CORS

We need to setup Cross-Origin Resource Sharing so that requests to our API are rejected, except when they come from our front end React application.

Make the following changes to config/cors.php.

'paths' => ['api/*', 'sanctum/csrf-cookie'],
    'allowed_methods' => ['*'],
    'allowed_origins' => ['', 'http://localhost:3000'],
    //'allowed_origins' => ['*'],
    'allowed_origins_patterns' => [],
    'allowed_headers' => ['*'],
    'exposed_headers' => [],
    'max_age' => 0,
    'supports_credentials' => true,

Modify paths to indicate which endpoints need to be protected: in this case api/* and sanctum/csrf-cookie.

'paths' => ['api/*', 'sanctum/csrf-cookie'],

Modify allowed-origins to specify the urls from which requests will be accepted. This will be the production and development urls of your React app, (for my app) and http://localhost:3000.

'allowed_origins' => ['', 'http://localhost:3000'],

Then set support_credentials to true.

'supports_credentials' => true,

User Controller

Next, create the User controller.

php artisan make:controller UserController

Edit app/Http/Controllers/UserController so that it looks like this.


namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use App\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;

class UserController extends Controller
    public function register(Request $request)
        $user = $this->create($request->all());
        return response()->json([
            'user' => $user,
            'message' => 'registration successful'
        ], 200);
     * Get a validator for an incoming registration request.
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
    protected function validator(array $data)
        return Validator::make($data, [
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
            //'password' => ['required', 'string', 'min:4', 'confirmed'],
            'password' => ['required', 'string', 'min:4'],

     * Create a new user instance after a valid registration.
     * @param  array  $data
     * @return \App\User
    protected function create(array $data)
        return User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => Hash::make($data['password']),
    protected function guard()
        return Auth::guard();

    public function login(Request $request)
        $credentials = $request->only('email', 'password');

        if (Auth::attempt($credentials)) {
            // Authentication passed...
            $authuser = auth()->user();
            return response()->json(['message' => 'Login successful'], 200);
        } else {
            return response()->json(['message' => 'Invalid email or password'], 401);

    public function logout()
        return response()->json(['message' => 'Logged Out'], 200);

The controller contains the register, login, and logout methods that will be called by our front end. It also contains a validator method to validate the data and a create method to add a new user to the database.

API Routes

Now we update routes/api as follows.

Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();

Route::post('/login', 'UserController@login');
Route::post('/register', 'UserController@register');
Route::get('/logout', 'UserController@logout');

The /user route is modified to make use of the Sanctum middleware we just installed. The front end app will not be able to get a successful response from this endpoint unless the user has first authenticated. If we were building a full blown API, all of the API routes would be protected with the Sanctum middleware.

We have also added three new endpoints to provide access to the login, register, and logout functions. Please note that all endpoints in the routes/api.php file will be prefixed with "/api". Therefore, the endpoint for the login route is "/api/login", the endpoint for the register route is "/api/register", and so forth.

Add a New User for Testing

At this point Laravel is completely set up to handle user authentication. Let's add a new user to the database so that we can test our setup. We can use tinker to accomplish this.

php artisan tinker

factory(App\User::class)->create(['email'=>'','name'=>'Bill', 'password'=> bcrypt('bill')]);

exit     (to leave tinker)

Part 2

The back end is finished and we're now ready to build the front end. In part two, we will walk through the tasks required to create a React app, with forms for user registration, login, and logout.

Top comments (6)

coopercodes profile image
🧸 🏳️‍🌈 cooper-codes 💻 🎮

Hi, great article, this is really helping me demistify a lot of the process (still new to Laravel).
Just wanted to let you know, if you are on Laravel 8+ that tinker command wont work to create a user, but i found the solution and thought I'd leave it here for others that may get stuck.

User::factory()->create(['email'=>'', 'name'=>'Bill', 'password'=> bcrypt('password')]);
Enter fullscreen mode Exit fullscreen mode
webprogrammerio profile image

Yes, I found the same thing with Laravel 9. Luckily I found your solution

santiagazo profile image
Jay L • Edited

Bob, awesome tut. Thank you so much. I've gone through a few of these laravel/sanctum SPA auth tuts and I keep running into the same problem. I can create the user and log in but anytime I try to hit the middleware route (in this case api/user) I get the response "unauthenticated".

I used your gitLab examples to ensure I had everything working correctly. I've updated the CORS file with allowed_origins => ['*'], I have added to my .env the following two lines:

They appear to be working correctly since I can login and get a successful message back. The referee (sanctum_stateful_domains) is exactly what's shown in my chrome developer tools.

I am getting back the x-xsrf-token and it shows that it's getting sent in the request headers to the api/user route too (see image)

Nonetheless, unauthenticated is what I get returned. I'm missing something. Every time I've done this, I've ended up here. Any ideas? Is there something I have wrong with my server-side code?

wmdarrigo profile image
William D'Arrigo

I have the same issue. Found anything?

malitov profile image
Pavlo Malitov

Cool! Thanks.
Waiting for the second part :)

yornletard profile image

You'll find an answer here: