Laravel API/w Sanctum and VueJS Front-End App/w Nuxt

With this post I want to go through the process of setting up a Laravel API using Sanctum for Authentication together with a VueJS Frontend app using the Nuxt VueJS Framework.

Table of contents


📢 Quick note on Cross-Origin Resource Sharing(CORS) and this development environment.

Oh man, when it comes to consuming your API from your own, so-called, first-party Single Page Application (SPA), getting the CORS configuration right is probably the thing that causes the most confusion.

Generally, browsers block Cross-Origin requests if the domain for both the API and SPA does not match. We'll configure this as well, but note, it can get tricky, at least, for me it was.

The Laravel API will run using Valet at hostname https://api.app.test and the Vue Frontend on  https://app.test:3000. The port also needs to be configured correctly.

So, as this guide is for a Development environment, you would need to adapt some steps for a Production environment. For example,  I used the .test TLD throughout the guide and port 3000 for the frontend, so take note of this and make the necessary updates based on your environment / needs.


Laravel

Laravel - The PHP Framework For Web Artisans

Install Laravel

First things first, I am not going to go into too much detail here, but I made use of Laravel Valet to get a Laravel instance up and running.

# Let's add a variable, because we are going to copy and paste a lot.

app=app

# Create a directory and navigate to it.

mkdir $app && cd $app

# Use the Laravel command to scaffold a new Laravel app.

laravel new api.$app

# Navigate to the new app's directory.

cd api.$app

# Use the Valet link command to link the new app.

valet link

Something like this 👇

The last thing I consider to be part of the Laravel installation is to make a few changes to the .env file.

There are a few things to add/change:
I am making an assumption that most readers already know what is going on here, if not, take a look here.

Variable Value Description
APP_NAME app The name of the app
APP_URL http://api.app.test The URL where the App lives
SESSION_DOMAIN .app.test Needed for Sanctum and CORS
SANCTUM_STATEFUL_DOMAINS app.test:3000 Needed for Sanctum and CORS
DB_DATABASE app Database Name
DB_USERNAME app Database Username
DB_PASSWORD app@Pass1234 Database Password

I usually make use of the following few lines of sed; and most of the variables are set using the bash variable we set at the start of the installation of the Laravel App.

sed -i '' \
    -e "s/^APP_NAME=Laravel$/APP_NAME=$app/" \
    -e "s/^APP_URL=http:\/\/localhost$/APP_URL=http:\/\/api.$app.test/" \
    -e '/^APP_URL=http.*$/a\
        SESSION_DOMAIN=.'$app'.test \
        SANCTUM_STATEFUL_DOMAINS='$app'.test:3000' \
    -e "s/^DB_DATABASE=laravel$/DB_DATABASE=$app/" \
    -e "s/^DB_USERNAME=root$/DB_USERNAME=$app/" \
    -e "s/^DB_PASSWORD=$/DB_PASSWORD=$app@Pass1234/" .env

Authentication Scaffolding

We'll make use of the Laravel UI package to scaffold authentication. We won't be using the views that the command creates, we are only looking for the Auth Controllers.

These controllers are useful, as will become apparent when we list the added routes, but everything is taken care of in this way compared to rolling out our own Register and Login controllers (that is where most people stop). What I mean by that is that this approach gives us not only Register and Login, but everything from password reset to email verification.  

The following commands will configure everything we require.

# Add the Laravel UI package

composer require laravel/ui

# Scaffold the necessary controllers for the middleware.

php artisan ui bootstrap --auth

To see all the new routes use php artisan route:list.

You may have noticed that the output instructs that we should run npm install && npm run dev, however, as we are only looking for the Auth Controllers to use with the Laravel API, we can safely ignore this. In fact, we can also remove the additions which have been added to packages.json by running the following sed command. In fact, we are not going to make use of any of the packages described in packages.json so it can safely be ignored.

sed -i '' \
    -e '/bootstrap/d' \
    -e '/jquery/d' \
    -e '/popper/d' package.json

Database setup and Migration

Alright, the last part required for creating a basic Laravel app starting point is to create a database, assign permissions, and run the Laravel migrations.

# Create Database

mysql -u root <<-EOF
CREATE DATABASE $app;
CREATE USER $app@'localhost' IDENTIFIED BY '$app@Pass1234';
GRANT ALL PRIVILEGES ON $app . * TO $app@'localhost';
FLUSH PRIVILEGES;
EOF

# Run migrations

php artisan migrate

Laravel API Sanctum Authentication

Laravel Sanctum - Laravel - The PHP Framework For Web Artisans

Sanctum Installation

The installation is clearly outlined in the Laravel Sanctum Installation documentation, but there are basically 3 required steps.

# Install / Add the Laravel Sanctum package using composer.

composer require laravel/sanctum

After running the above command, you'll notice the middleware for our routes have changed from before, see php artisan route:list.

# Publish the Sanctum config to the Laravel app.

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

# Migrate the Sanctum tables.

This is actually optional as its only required if we want to use tokens and not cookies, but I do not want hiccups later should I need it.

php artisan migrate

Enable Sanctum Middleware

Enable the Sanctum middleware to the API middleware group within the app/Http/Kernel.php file, see # comments:

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

# Add this line in the Use block
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;

class Kernel extends HttpKernel
{

    [...SNIP...]
    
    protected $middlewareGroups = [
    
        [...SNIP...]
        
        'api' => [
        	# The following line should be added to the
			# protected $middlewareGroups section.
    		EnsureFrontendRequestsAreStateful::class,
            
            'throttle:60,1',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];
    
    [...SNIP...]
    
}

Configure CORS

👉 During our .env update section above we have already added the SESSION_DOMAIN and SANCTUM_STATEFUL_DOMAINS configuration, but that was actually a Sanctum config.

So all that remains is to update a few sections within config/cors.php.

  1. We need to update the paths as described below, as well as
  2. Enable support for credentials.
<?php

return [

    'paths' => [
        'api/*', 
        'sanctum/csrf-cookie', 
        'login', 
        'logout', 
        'register', 
        'password/*'
    ],

    [...SNIP...]

    'supports_credentials' => true,

];

Update Route Authentication Middleware

Lastly, within the routes/api.php we need to specify that the routes make use of the Sanctum auth middleware, so we'll replace the auth:api middleware with auth:sanctum.

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

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

Postman

Postmap is a neat app for interacting with APIs. See the bookmark below to find out more or to download the latest version.

Postman | The Collaboration Platform for API Development
Simplify each step of building an API and streamline collaboration so you can create better APIs—faster

Postman Collection

To make things a little easier I created a Postman collection to import into Postman.

We'll use the Import feature towards the top-left and specify the URL to the Postman collection in the Link tab of the Import window.

Import Collection

Variables

Once the Collection has been imported, update the variables within the collection's variables tab from the edit window. Update the host and base_url variables:

Navigating to the Variables section
Updating the Variables if required

Endpoints

With that we have the following basic auth endpoints:

  • POST Register
  • POST Login
  • GET User
  • POST Logout

Using the Register request, update the values as desired and create a user by using the send button. In the response pane (to the bottom) a 201 Created is what we want to see. :)

Registering User

Using the User request, we get the details of the currently signed in user. By default after a user is created, they are automatically signed in. But you are welcome to first use the Logout request to log back in before viewing the user.
NOTE: The Referrer Header should be set to host, it should match the environment variable SANCTUM_STATEFUL_DOMAINS set in the Laravel .env file.

Get User details from user endpoint

With this we have confirmed that the API with Sanctum Authentication work as expected and I suggest that this collection be built on as you develop the API further.


Nuxt VueJS Frontend

The last part is to create a Frontend app to interact with the API, and for that we'll make use of the VueJS Nuxt Framework.

Nuxt.js - The Intuitive Vue Framework
Build your next Vue.js application with confidence using NuxtJS. An open source framework making web development simple and powerful.

Installation

# To install, we'll go up one directory and run the Nuxt installer.

During the installation, we'll be prompted for a few installation options, you are welcome to select the options best suited to your needs.
NOTE: See the cast below for the options I prefer.

cd ../
npx create-nuxt-app $app

# I prefer to remove the .git directory at this point and add it later when I am ready.

cd $app
rm -rf .git

Configure Hostname for CORS

As we are still running in a Development environment, let us update the dev command in the packages.json to start the dev server using the same host.

As mentioned before, CORS causes some complication, so take note of what is required to be updated, especially when you start moving the API and the App to production.

sed -i '' "s/\"dev\": \"nuxt\"/\"dev\": \"nuxt --hostname $app.test\"/" package.json

When running npm run dev we'll confirm that we can access http://app.test:3000, instead of http://localhost:3000, which is needed so that we do not receive any CORS errors.

Access app on hostname and not localhost

Configure Axios

We can now set the baseURL for axios and enable credentials. This is required for the API (Sanctum).

Within the nuxt.config.js we add the following to the axios section.
🚨 Make sure the URL is correct, in this example I used app.

{
   [...SNIP...]
   axios: {
     baseURL: 'http://api.app.test/',
     common: {
       Accept: 'application/json, text/plain, */*'
     },
     credentials: true
   },
   [...SNIP...]
}

The sed command below can also be used to update the configuration.

sed -i '' 's/axios: {},/axios: {\
     baseURL: '"'http:\/\/api.$app.test\/'"',\
     common: {\
       Accept: '"'application\/json, text\/plain, *\/*'"'\
     },\
     credentials: true\
   },/' nuxt.config.js

API Authentication with Nuxt Auth

There is a Nuxt community project which enables Authentication support to the Nuxt application. It's basically 2 steps, install and config.

Auth Module | Auth Module
Authentication module for Nuxt

# Install the module.

npm install @nuxtjs/auth

# Add the module and it's configuration to nuxt.config.js.

{
   [...SNIP...]
   /*
   ** Nuxt.js modules
   */
   modules: [
     [...SNIP...]
     // Doc: https://auth.nuxtjs.org/
     '@nuxtjs/auth'
   ],
   [...SNIP...]
   /*
   ** Auth module configuration
   ** See https://auth.nuxtjs.org/schemes/local.html#options
   */
   auth: {
     strategies: {
       local: {
         endpoints: {
           login: { url: '/login', method: 'post' },
           logout: { url: '/logout', method: 'post' },
           user: { url: '/api/user', method: 'get', propertyName: false}
         },
         tokenRequired: false,
         tokenType: false
       }
     }
   },
}

The sed commands below can also be used to update the configuration.

sed -i '' 's/'"'@nuxtjs\/axios'"'/'"'@nuxtjs\/axios'"',\
    \/\/ Doc: https:\/\/auth.nuxtjs.org\/\
    '"'@nuxtjs\/auth'"'/' nuxt.config.js
sed -i '' 's/credentials: true/credentials: true\
   },\
   \/*\
   ** Auth module configuration\
   ** See https:\/\/auth.nuxtjs.org\/schemes\/local.html#options\
   *\/\
   auth: {\
     strategies: {\
       local: {\
         endpoints: {\
           login: { url: '"'\/login'"', method: '"'post'"' },\
           logout: { url: '"'\/logout'"', method: '"'post'"' },\
           user: { url: '"'\/api\/user'"', method: '"'get'"', propertyName: false }\
         },\
         tokenRequired: false,\
         tokenType: false\
       }\
     }/' nuxt.config.js

Start Development Server

We are just about ready to run our dev server. The last step is to initiate the Vuex Store by creating a store/index.js  file and then we can start the dev server.

touch store/index.js
npm run dev

Starter Views

Now that our server is up and running, let's add some views for register and login, and get the user data.

NOTE: You can leave the dev server running, just open a new terminal window to curl the Vue components to the correct location. Make sure you are in the root directory of the Vue App, in my case it is ~/_Development/app/app. I have also added a demo of using the curl command at the end of this section.

default.vue

We'll add a Navbar to the default.vue file that is include with Nuxt.

Included the navbar

See the code snippet below to get an idea of what it looks like. However, to make things easier, I have created a gist which we can curl.

curl https://gist.githubusercontent.com/CryDeTaan/ef62bf007f0de76faf8ea9dbf69c2bc3/raw/8ab40794fb7fa47dc64f962649e8c6ad0e5fdf5d/default.vue -o layouts/default.vue

register.vue

Next is the register.vue file, I have hardcoded a username and password, THIS IS BAD, it's just to make the demo and getting started easier, so please update/remove it when you got the hang of this :)

Register page

Again, I have created a gist which we can curl.

curl https://gist.githubusercontent.com/CryDeTaan/ef62bf007f0de76faf8ea9dbf69c2bc3/raw/8ab40794fb7fa47dc64f962649e8c6ad0e5fdf5d/register.vue -o pages/register.vue

login.vue

Lastly, the login.vue file, and as with the register view, I have hardcoded the username and password just as an example, so please remove it from the data property.

Login page

Again, I have created a gist which we can curl.

curl https://gist.githubusercontent.com/CryDeTaan/ef62bf007f0de76faf8ea9dbf69c2bc3/raw/8ab40794fb7fa47dc64f962649e8c6ad0e5fdf5d/login.vue -o pages/login.vue

Curl Demo

The Final Product

With that we are done! We can now login and once logged in, you'll see the Get User details and the information can bee seen in developer tools. Nothing fancy, but good enough as a starter project.

Remember, this is just a proof of concept, so these views provide minimal functionality. For example, the get user button will not display the User's details, we'll just confirm we receive a response using the dev tools console. However, this could be used as a starting point to build on, should you wish to.

Get User button will show User details in console

If you enjoyed the post, please consider to subscribe so that you receive future content in your inbox :)

Psssst, worried about sharing your email address and would rather want to hide it? Consider using a service I created to help with that: mailphantom.io

Also, if you have any questions, comments, or suggestions please feel free to Contact Me.