How to authenticate APIs with Laravel (Sanctum) and Vue (Nuxt)
Thank you for your continued support.
This article contains advertisements that help fund our operations.
Table Of Contents
⇨ Click here for Laravel article table of contents ⇨ Click here for Vue article table of contents
Implementing API authentication using Laravel (Sanctum) and Nuxt's auth-module.
Introduction
What is Sanctum?
Sanctum is Laravel's simplest authentication package released from Laravel 8.
Previously, LaravelPassport was commonly used for API authentication packages, but it had too many features.
However, because it had too many features, it was difficult to use as the first choice.
With Sanctum, it is now possible to authenticate APIs more simply.
What is Nuxt-Auth-Module?
It is a standard package for storing authentication information in Nuxt.
This package is designed to make it easy to set up the Vue Auth-module package in Nuxt.
Overview of the Process
①Issuing a token for authentication in Laravel
②Storing the token in Nuxt-auth
This is the flow.
Let's first configure it on the Laravel side.
Laravel Configuration
Install the necessary components via commands.
Creating a project
composer create-project laravel/laravel laravel-api
Installing Sanctum
composer require laravel/sanctum
Setting up a local server
php artisan serve
The local server is set up:
Starting Laravel development server: http://127.0.0.1:8000
Allowing modification of the configuration file
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
A new file has been added to database/migrations which allows modification of personal_access_tokens.
Creating a database to store tokens
Create the personal_access_tokens table (by running the previous command).
Command:
php artisan migrate
If this command fails, it means there is an issue with the database connection.
Package Versions
"laravel/framework": "^8.75",
"laravel/sanctum": "^2.14",
Changes in App/Http/Kernel.php
Uncomment the commented part in the 'api' item around line 42:
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
Changes in App/Http/Middleware/VerifyCsrfToken.php
protected $except = [
'api/login'
];
This allows POST for login without authentication.
Configuring APItoken authentication in User model
Make sure that such a configuration is present in the User model.
Most likely, this is automatically done via commands.
App/Models/User.php
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
//Other code lines here
Creating Test User Data
Create test user data using the Seeder functionality.
How to prepare test data in Laravel (using Seeders)
Create a Seeder file via command
php artisan make:seeder UsersTableSeeder
database/seeders/UsersTableSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
//↓3 lines added
use Hash;
use DB;
use App\Models\User;
class UsersTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$data = [
[
'name' => 'laratechjp',
'email' => 'laratech@example.com',
'password' => Hash::make('password')
],
];
DB::table('users')->insert($data);
}
}
The Seeder above creates a user who can log in with:
email: laratech@example.com
password: password
Edit database/seeders/DatabaseSeeder.php
Only edit the necessary part:
public function run()
{
$this->call(UsersTableSeeder::class);
// \App\Models\User::factory(10)->create();
}
Command
Load the classes you have set up:
composer dump-autoload
Generate Data
php artisan db:seed
Adding Login Functionality in Laravel
Creating login route
routes/api.php
use App\Http\Controllers\Api\Auth\LoginController;
Route::post('/login',[LoginController::class,'login']);
Creating the login function
Assuming input fields for email and password:
Search for user by email ⇨ Compare stored password of the user
Writing the simplest function:
<?php
namespace App\Http\Controllers\Api\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
//Adding 2 lines
use Hash;
use Illuminate\Validation\ValidationException;
class LoginController extends Controller
{
public function login(Request $request)
{
$email = $request->email;
$password = $request->password;
$user = User::where('email', $email)->first();
if (! $user || ! Hash::check($password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['Incorrect email or password'],
]);
}
$token = $user->createToken('token')->plainTextToken;
return response()->json(compact('token'),200);
}
}
As mentioned in the API token issuance section
Nuxt Configuration
Creating the project
yarn create nuxt-app nuxt-api
Running a local host via command
yarn dev
Local host is set up:
Nuxt @ v2.15.8 │
│ │
│ ▸ Environment: development │
│ ▸ Rendering: server-side │
│ ▸ Target: static │
│ │
│ Listening: http://localhost:3000/
Installing nuxt-axios
Command:
yarn add @nuxtjs/axios
Adding nuxt-axios to nuxt.config.js
modules: ["@nuxtjs/axios"],
Specifying the base URL for axios (in this case, the address of Laravel's local server)
Add to nuxt.config.js
publicRuntimeConfig: {
axios: {
baseURL: process.env.BASE_URL,
},
},
Create a .env file
Create a file named .env at the root of the Nuxt project directory.
Add the following to .env:
BASE_URL=http://127.0.0.1:8000
Creating a login form
Create a pages/login/index.vue file
For those not using Vuetify, replace v-text-field with input tags.
<template>
<v-row>
<v-col class="text-center">
<v-text-field label="email" v-model="email"></v-text-field>
<v-text-field label="password" v-model="password"></v-text-field>
<v-btn @click="login" color="blue" outlined>Login</v-btn>
</v-col>
</v-row>
</template>
<script>
export default {
data() {
return {
email: "",
password: "",
}
},
methods: {
login() {
console.log("clicked")
this.$axios
.$post("/api/login", {
email: this.email,
password: this.password,
})
.then(response => {
console.log(response)
})
},
},
}
</script>
Trying to login
Enter:
laratech@example.com password
and click the button
If a token is returned in the console, it means the login was successful.
{token: '6|XTSYN6HylafFkHfgWHxoODrrfA3kDjlptQFPChaB'}
This completes the confirmation of operation.
The next step is to use the token in Nuxt to create an authentication feature.
Using nuxt-auth-module
Installing the package via command
Instructions can be found here
yarn add @nuxtjs/auth-next
Adding to nuxt.config.js
Make sure to consolidate the modules' settings within the modules list, which may already have axios added:
modules: ["@nuxtjs/axios", "@nuxtjs/auth-next"],
//Modules: https://auth.nuxtjs.org/schemes/local
auth: {
strategies: {
local: {
token: {
property: "token",
global: true,
},
user: {
property: "user",
},
endpoints: {
login: { url: "/api/login", method: "post" },
logout: { url: "/api/logout", method: "post" },
user: { url: "/api/user", method: "get" },
},
},
},
},
Displaying user information in Nuxt
When using in template
<template>
<div>
<p>{{ $auth.loggedIn }}</p>
<p>{{ $auth.user }}</p>
</div>
</template>
Display:
true (when authenticated, false when not authenticated)
{ "id": 1, "name": "laratechjp", "email": "laratech@example.com", ... }
When using in script
Just use this
:
<script>
export default {
created(){
console.log(this.$auth.user)
}
}
</script>
Writing Processes that Only Users Not Logged In Can Access
Laravel
Add settings to .env
Specify the Nuxt path in .env:
SESSION_DOMAIN=http://127.0.0.1:3000
SANCTUM_STATEFUL_DOMAINS=http://127.0.0.1:3000
After changing .env, run the command:
php artisan config:cache
The changes will be reflected in config/session.php and config/sanctum.
Update api.php
Add a line for post:
Route::group(['middleware' => 'auth:sanctum'],function(){
Route::get('/user',[UserController::class,'index']);
Route::post('/post',[PostController::class,'store']);
});
Create the controller
php artisan make:controller Api/PostController
Write in App/Http/Controller/Api/PostController.php
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function store(Request $request)
{
$content = $request->content;
$user = $request->user();
return response()->json(compact('content','user'),200);
}
}
Nuxt
<template>
<v-btn @click="post">Post!</v-btn>
</template>
<script>
export default {
data() {
return {
content: "Test post",
}
},
methods: {
post() {
this.$axios
.$post("/api/post", {
content: this.content,
})
.then(response => {
console.log(response)
})
},
},
}
</script>
Result:
content: "Test post",
user: {id: 1, name: 'laratechjp', email: 'laratech@example.com', ....
That's it, well done!
Conclusion
That's all.
I have posted the code on GitHub:
For feedback or complaints, please contact me via Youtube Comment!
Thank you and goodbye!
Top Articles:
Deploying a PHP7.4 + Laravel6 Project to AWS EC2
Implementing Breadcrumbs in Laravel with laravel-breadcrumbs