How to protect Ajax server-side processing for jQuery DataTables using API Tokens in Laravel 7

Carlos Panganiban
3 min readJun 14, 2020

--

This tutorial assumes you already know how to set up jQuery DataTables for your webpage, and at the least basic Laravel knowledge. The authentication will be token-based, and knowledge of Laravel Passport is not required.

Security concerns: This authentication solution is “easier” to do, compared to authentication using Laravel Passport, but using the latter would be more secure. Laravel’s API Token guard should only be used for trivial authentication, and NOT for authentication involving sensitive user data, etc.

Set up the configuration files

Before we get started, it is important to know that Laravel (or the version of it I’m using, which is Laravel 7.x) automatically handles API authentication through its routes by using the pre-set middleware auth:api.

To make sure that we use Laravel’s built-in API token authentication driver (or in some cases, people call this the “guard”), we edit config/auth.php like so:

'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],

'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],

Note that for most projects, this is the default setting.

Set up the database

Then, it is crucial to set up the database so it can hold API tokens for authentication. Laravel handles this automatically, and by default looks at the api_token field in the database. If you use a different field name, then the default guard is not guaranteed to work.

For instance, in my create_users_table.php migration, I add the field like so:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration
{
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->string('api_token', 80)->unique()
->default(Str::random(80));
$table->rememberToken();
$table->timestamps();
});
}
}

The field is a string, with the name api_token with length 80 (hence string('api_token', 80)), is unique (hence unique()), and lastly, is randomized by default (hence default(Str::random(80)).

Setting up the routes

First, the page should be in a protected route (like a logged-in user-only route), or else authenticating the API would be pointless in the first place. In this example, my protected page will be ShoppingController@index.

In your routes/web.php:

Route::group(['middleware' => ['auth']], function() {
Route::get('/shopping', 'ShoppingController@index')
->name('shopping.index');
});

Second, we make sure that the built-in token guard for Laravel is utilized for the API route. For this example, my API endpoint for my DataTables processing will be ShoppingController@ajax.

We set the API endpoint in routes/api.php with the auth:api middleware like so:

Route::middleware('auth:api')->get('/list, 'ShoppingController@ajax')->name('api.list');

The routes we will be using should now be properly set up.

Passing the API token to the frontend

We will use the default Blade templating engine for the frontend. To get the currently logged-in user’s api_token, we can call this:

{{ Auth::user()->api_token }}

That being said, we should be able to pass this token to our request with DataTables:

$('#list_table').DataTable({
"processing": true,
"serverSide": true,
"ajax": {
"url": "{{ route('api.list') }}",
"type": "GET",
"data": {"api_token": {{ Auth::user()->api_token }}},
},
"columns": [
... whatever you put here ...
]
});

And that should pass the api_token parameter in the GET request.

That’s it!

There are many things you could do to improve on approaching this.

References

--

--