close icon
Laravel

Build and Secure a Laravel API

Learn how to build and secure an API with Laravel.

Last Updated On: May 13, 2021

Getting Started

In this tutorial, you'll learn how to create a simple Laravel API and add authorization to it using Auth0. You can find the final code in this GitHub repository.

šŸ‘‹ If you already have a Laravel API that you want to secure, you can go ahead and skip to the "Secure your Laravel API" section.

Prerequisites

This tutorial uses the latest version of Laravel at the time of writing (v8). I will assume you have some basic knowledge of Laravel. If you're new to Laravel, Build a Laravel CRUD Application with Authentication may be a better primer for you!

You'll also need the following:

What you'll build

You'll be building a simple API with a single /comment resource. The API should allow anyone to view comments. However, only authorized users should be able to create, update, or delete a comment.

Public endpoints:

  • GET /comments ā€” Return all comments
  • GET /comments/{id} ā€” Return the comment with the specified id

Private endpoints:

  • POST /comments ā€” Add a new comment
  • PUT /comments/{id} ā€” Update the comment with the specified id
  • DELETE /comments/{id} ā€” Delete the comment with the specified id

Setting Up Your Laravel Application

Installation

First, start by creating your new Laravel application. Make sure you have Composer installed, and then run the following:

composer create-project laravel/laravel laravel-api-auth
cd laravel-api-auth
php artisan serve

You can now view your starter Laravel application at http://localhost:8000!

Laravel starter app

šŸ‘©ā€šŸ’» Tip: There are several other options for starting a new Laravel project. You can now even run your Laravel project with Docker using the brand new Laravel Sail.

Sign up for Auth0

Next, you need to sign up for a free Auth0 account if you don't already have one.

Your free account allows you to easily add authentication and authorization to your applications. You'll also have access to:

You'll go through a short sign-up process where you'll create your Auth0 tenant. Once you've finished, leave the dashboard open, as you'll be revisiting it soon.

Create the Database

For this tutorial, you'll be using SQLite as the database. In your terminal, run:

touch database/database.sqlite

This will create the .sqlite file at database/database.sqlite. Next, open up .env and find the section that specifies the database. Update it as follows:

DB_CONNECTION=sqlite
DB_DATABASE=/absolute/path/to/database.sqlite

Note: You need to use the absolute path to the database.sqlite file you just created as the value for DB_DATABASE. You can usually get this by right-clicking the file in your code editor and clicking "Copy path".

Models, Migrations, Factories, and Seeding

Next, you need to set up the Comment model, migration, factory, and seeder. You can do this all with one command, but let's go over each individually.

šŸ‘©ā€šŸ’» Tip: To create a model, factory, migration, seeder, and controller all with a single Artisan command: php artisan make:model Comment -mfsc

Create Comment model

In your terminal, run the following:

php artisan make:model Comment

Open up the model file that was created at app/Models/Comment.php and replace it with the following:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
  use HasFactory;

  protected $fillable = [
    'name',
    'text'
  ];
}

In Laravel, the model name is written in singular camel-case. This way, it can be automatically matched up to its corresponding database table, which is assumed to be singular snake-case.

In other words, the Comment model corresponds to the comments table in the database.

A comment in this API is very simple. It will have the following attributes:

  • id ā€” Primary key
  • created_at ā€” Comment creation date
  • updated_at ā€” Comment updated date
  • name ā€” Name of the commenter
  • text ā€” Comment text

You'll notice that only name and text are listed as fillable, with no mention of the other attributes. This is because Laravel assumes that id, created_at, and updated_at exist in your table and will automatically update them when a model is created.

šŸ‘©ā€šŸ’» Tip: If you don't want an auto-incrementing primary key, set public $incrementing = false;. If you don't want automatic timestamps, set public $timestamps = false;.

Create Comment migration

Next, it's time to create the migration. In your terminal, run the following:

php artisan make:migration create_comments_table

This will create a new file in the database/migrations directory. The filename will start with the timestamp of when the file was created, followed by create_comments_table.php. When you run your migrations, they'll be run based on the timestamp from earliest to most recent.

Open the file up and replace it with the following:

<?php

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

class CreateCommentsTable extends Migration
{
  /**
    * Run the migrations.
    *
    * @return void
    */
  public function up()
  {
    Schema::create('comments', function (Blueprint $table) {
      $table->id();
      $table->timestamps(); // created_at and updated_at
      $table->string('name');
      $table->string('text');
    });
  }

  /**
    * Reverse the migrations.
    *
    * @return void
    */
  public function down()
  {
    Schema::dropIfExists('comments');
  }
}

Here, you're using the Schema facade with the create method to create the comments table in the database. You're then able to define the table columns using the schema builder's column methods. In this case, you're creating the id, created_at, updated_at, name, and text columns. The last two will get a type of string.

Now, run the migration in your terminal with:

php artisan migrate

Comment seeder

When you're testing your application, it's helpful to have some mock data in your database. This is where the seeder comes into play. By creating a seeder, you can easily add mock data to your database with a single command.

In a large application, you can create separate seeder files for every model by running php artisan make:seeder CommentSeeder. For our purposes, putting the seeder in the main DatabaseSeeder.php file is fine.

Open up /database/seeders/DatabaseSeeder.php and update it as follows:

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use App\Models\Comment;

class DatabaseSeeder extends Seeder
{
  /**
    * Seed the application's database.
    *
    * @return void
    */
  public function run()
  {
    Comment::factory()
      ->times(3)
      ->create();
  }
}

When you run the seeder, the run method will execute, which is where the mock data is created. Instead of manually creating mock data for every table, you can use Eloquent model factories to define the guidelines for this mock data. Let's define the factory now.

Create Comment factory

Create your Comment factory by running the following:

php artisan make:factory CommentFactory

Open up the newly generated factory file in database/factories/CommentFactory.php and replace it with the following:

<?php

namespace Database\Factories;

use App\Models\Comment;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class CommentFactory extends Factory
{
  /**
    * The name of the factory's corresponding model.
    *
    * @var string
    */
  protected $model = Comment::class;

  /**
    * Define the model's default state.
    *
    * @return array
    */
  public function definition()
  {
    return [
      'name' => $this->faker->name,
      'text' => $this->faker->text()
    ];
  }
}

In the definition method, you're returning the two attributes, name and text, with their mock data. The mock data is generated using the PHP Faker library.

Back in the DatabaseSeeder.php file, you have this run method:

public function run()
{
  Comment::factory()
    ->times(3)
    ->create();
}

Now, when you run the seeder, it will run this Comment model factory three times, thus creating three entries in the comments table.

Let's test it out now by running the following:

php artisan db:seed

To confirm that it was created, you can use Tinker, which allows you to interact with your Laravel application from the command line.

In your terminal, run:

php artisan tinker

This will open up Tinker. Next, enter:

App\Models\Comment::all()

This will return the Eloquent collection with existing comments:

Illuminate\Database\Eloquent\Collection {
  all: [
    App\Models\Comment {#4262
      id: "1",
      created_at: "2020-12-08 19:57:33",
      updated_at: "2020-12-08 19:57:33",
      name: "Eleonore Kohler",
      text: "Dolor rerum saepe rerum pariatur. Corporis eos unde eveniet itaque aut omnis voluptas.",
    },
    App\Models\Comment {#4263
      id: "2",
      created_at: "2020-12-08 20:01:32",
      updated_at: "2020-12-08 20:01:32",
      name: "Mr. Alfonso Schmidt",
      text: "Iste dolores reiciendis eius dolorem dolorem qui et mollitia. Vel deserunt ea deleniti ipsam fugiat. Velit assumenda odio ipsum qui nisi voluptatem molestiae.",
    },
    App\Models\Comment {#4264
         id: "3",
         created_at: "2020-12-08 21:56:52",
         updated_at: "2020-12-08 21:56:52",
         name: "Ms. Destany Kozey DDS",
         text: "Rem reprehenderit voluptas quasi est ea. Quibusdam accusamus et dolores porro veritatis quo eos. Et beatae et voluptatem voluptatem aperiam dolores fugit.",
       },
     ],
  ]
}

You can exit Tinker by typing in exit.

Now that all the heavy lifting is done, let's set up the API!

Create the Comment Controller

First, you need to create the Comment controller. In your terminal, run the following:

php artisan make:controller API/CommentController --resource

This will create a new file at app/Http/Controllers/API/CommentController.php, complete with all of the methods you'll need.

Open this up now and update it as follows:

<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use App\Models\Comment;
use Illuminate\Http\Request;

class CommentController extends Controller
{
  /**
    * Display a listing of the resource.
    *
    * @return \Illuminate\Http\Response
    */
  public function index()
  {
    $comments = Comment::all();
    return response()->json($comments);
  }

  /**
    * Store a newly created resource in storage.
    *
    * @param  \Illuminate\Http\Request  $request
    * @return \Illuminate\Http\Response
    */
  public function store(Request $request)
  {
    $request->validate([
      'name' => 'required|max:255',
      'text' => 'required'
    ]);

    $newComment = new Comment([
      'name' => $request->get('name'),
      'text' => $request->get('text')
    ]);

    $newComment->save();

    return response()->json($newComment);
  }

  /**
    * Display the specified resource.
    *
    * @param  int  $id
    * @return \Illuminate\Http\Response
    */
  public function show($id)
  {
    $comment = Comment::findOrFail($id);
    return response()->json($comment);
  }

  /**
    * Update the specified resource in storage.
    *
    * @param  \Illuminate\Http\Request  $request
    * @param  int  $id
    * @return \Illuminate\Http\Response
    */
  public function update(Request $request, $id)
  {
    $comment = Comment::findOrFail($id);

    $request->validate([
      'name' => 'required|max:255',
      'text' => 'required'
    ]);

    $comment->name = $request->get('name');
    $comment->text = $request->get('text');

    $comment->save();

    return response()->json($comment);
  }

  /**
    * Remove the specified resource from storage.
    *
    * @param  int  $id
    * @return \Illuminate\Http\Response
    */
  public function destroy($id)
  {
    $comment = Comment::findOrFail($id);
    $comment->delete();

    return response()->json($comment::all());
  }
}

Let's go over each method in this controller.

index() method:

public function index()
{
  $comments = Comment::all();
  return response()->json($comments);
}

This will be used to get all comments. You're using the Eloquent all() method on the Comment model, which will return all results in the comments table. Then, you're returning the comments as a JSON response.

store() method:

public function store(Request $request)
{
  $request->validate([
    'name' => 'required|max:255',
    'text' => 'required'
  ]);

  $newComment = new Comment([
    'name' => $request->get('name'),
    'text' => $request->get('text')
  ]);

  $newComment->save();

  return response()->json($newComment);
}

The store() method is used to create a new comment. You can use the validate() method to set validation rules for incoming requests. For this example, you're just setting name and text as required and limiting the name field to 255 characters. If the validation fails, the error will be automatically sent back to the view.

If the validation passes, a new comment is created and saved to the database. The new comment is then returned as a JSON response.

show(id) method:

public function show($id)
{
  $comment = Comment::findOrFail($id);
  return response()->json($comment);
}

The show() method is used to get a single comment. It accepts the id of the requested comment and then uses Eloquent's findOrFail() method to find the comment in the database.

update(id) method:

public function update(Request $request, $id)
{
  $comment = Comment::findOrFail($id);

  $request->validate([
    'name' => 'required|max:255',
    'text' => 'required'
  ]);

  $comment->name = $request->get('name');
  $comment->text = $request->get('text');

  $comment->save();

  return response()->json($comment);
}

The update() method is similar to store(), but instead of creating a new comment, you first grab the existing requested comment with findOrFail($id). You then validate the new request, update the existing comment if the request is valid, save it in the database, and return the updated comment.

destroy(id) method:

public function destroy($id)
{
  $comment = Comment::findOrFail($id);
  $comment->delete();

  return response()->json($Comment::all());
}

Finally, you have the destroy() method. This takes the id of the comment that is being deleted, finds the comment, deletes it, and returns all comments so that you can verify that the deleted comment no longer exists.

Create the API Routes

Finally, let's set up the API routes.

Open up routes/api.php and replace everything with the following:

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\API\CommentController;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::apiResource('comments', CommentController::class);

Using Route::apiResource() here creates all of the routes needed to create, show, update, and delete comments.

You can see all of the routes in your application by running:

php artisan route:list

PHP route list

You'll also notice that everything is going in the api.php file instead of the commonly used web.php file. By placing the API routes in the api.php file, you get the following:

  • An /api prefix, e.g., yourdomain.com/api/comments
  • Throttle middleware is automatically applied
  • No automatic session state and CSRF protection, like you would get with routes/web.php

Next, let's test out the API to make sure everything works.

Testing your API

You can confirm that your API works correctly by using a tool such as Postman or testing from your terminal with cURL. I'll show the cURL commands first and then the Postman instructions at the end of the section if you prefer using that approach.

As a reminder, here are the API endpoints that were created:

  • GET https://localhost:8000/api/comments ā€” Return all comments
  • GET https://localhost:8000/api/comments/{id} ā€” Return the comment with the specified id
  • POST https://localhost:8000/api/comments ā€” Add a new comment
  • PUT https://localhost:8000/api/comments/{id} ā€” Update the comment with the specified id
  • DELETE https://localhost:8000/api/comments/{id} ā€” Delete the comment with the specified id

cURL commands

Get all comments:

curl http://localhost:8000/api/comments -i

Response:

[
    {
        "id": 1,
        "created_at": "2021-03-03T21:31:36.000000Z",
        "updated_at": "2021-03-03T21:31:36.000000Z",
        "name": "Dee Sporer",
        "text": "Quod nam qui modi sunt. Illum ut delectus minima nisi corporis assumenda voluptate. Quaerat voluptate omnis vitae ex."
    },
    {
        "id": 2,
        "created_at": "2021-03-03T21:31:36.000000Z",
        "updated_at": "2021-03-03T21:31:36.000000Z",
        "name": "Lurline Schinner",
        "text": "Culpa blanditiis nihil quisquam minima nam. Rerum placeat vero corrupti nobis reiciendis accusantium necessitatibus. Maiores vel nesciunt voluptatum ex. Eveniet quidem aut neque."
    },
    {
        "id": 3,
        "created_at": "2021-03-03T21:31:36.000000Z",
        "updated_at": "2021-03-03T21:31:36.000000Z",
        "name": "Pete McClure MD",
        "text": "Amet impedit mollitia consectetur eveniet natus. Cumque perspiciatis debitis ratione est. Dolor expedita vitae recusandae ut quos earum."
    }
]

Get a single comment:

curl http://localhost:8000/api/comments/1 -i

Response:

{
    "id": 1,
    "created_at": "2021-03-03T21:31:36.000000Z",
    "updated_at": "2021-03-03T21:31:36.000000Z",
    "name": "Dee Sporer",
    "text": "Quod nam qui modi sunt. Illum ut delectus minima nisi corporis assumenda voluptate. Quaerat voluptate omnis vitae ex."
}

Create a comment:

curl -X POST -H 'Content-Type: application/json' -d '{
    "name": "Holly",
    "text": "You are the best!"
}' http://localhost:8000/api/comments -i

Response:

{
  "name": "Holly",
  "text": "You are the best!",
  "updated_at": "2021-03-03T23:16:31.000000Z",
  "created_at": "2021-03-03T23:16:31.000000Z",
  "id": 4
}

Update a comment:

curl -X PUT -H 'Content-Type: application/json' -d '{
  "name": "Holly",
  "text": "My updated comment"
}' http://localhost:8000/api/comments/4 -i

Response:

{
  "id": 4,
  "created_at": "2021-03-05T13:41:17.000000Z",
  "updated_at": "2021-03-05T13:51:40.000000Z",
  "name": "Holly",
  "text": "My updated comment"
}

Delete a comment:

curl -X DELETE http://localhost:8000/api/comments/4 -i

Response:

[
  {
    "id": 1,
    "created_at": "2021-03-05T14:27:49.000000Z",
    "updated_at": "2021-03-05T14:27:49.000000Z",
    "name": "Burdette Medhurst",
    "text": "Hic dolores minus illum modi consectetur. Qui est officia distinctio voluptatem at aut non. Sapiente perspiciatis nesciunt ea eos. Perferendis dolorem harum rerum magnam totam."
  },
  {
    "id": 2,
    "created_at": "2021-03-05T14:27:49.000000Z",
    "updated_at": "2021-03-05T14:27:49.000000Z",
    "name": "Keaton Wuckert",
    "text": "Id distinctio rerum tenetur et. Molestias excepturi aut labore enim. Vitae aperiam aut odit sed. Qui est sit cupiditate ut placeat sint nam."
  },
  {
    "id": 3,
    "created_at": "2021-03-05T14:27:49.000000Z",
    "updated_at": "2021-03-05T14:27:49.000000Z",
    "name": "Violet Kulas",
    "text": "Nostrum adipisci tempora tempore ad et. Quia minus odit rem. Non nihil maiores quidem eum molestiae voluptatem cum."
  }
]

Postman instructions

Open up Postman and create a new GET request at https://localhost:8000/api/comments. Click "Send", and you should see the JSON response of all the comments in your application.

Postman GET comments request

You can test getting a single comment with https://localhost:8000/api/comments/1.

To test creating a new comment, change the request to a POST request and type in http://localhost:8000/api/comments/ as the request URL. Next, click on "Body" and enter in name and text as the keys with any string as the value. Click "Send" to create the new comment, and you'll see the new comment returned below.

Postman create comment

Just to confirm, switch back to a GET request and get all the comments again. You should see your new comment now listed.

You can also easily update and delete comments using this same method, but make sure you change the HTTP verb to PUT or DELETE, respectively.

Secure your Laravel API

šŸ’ƒ You finally have a fully functional API!

However, we can't celebrate just yet. If you recall, one of the application constraints was that some of these API endpoints should be private. Currently, anyone can perform any operation on your API. Let's fix that.

Configure Auth0

You're going to be using Auth0 to protect the private endpoints. If you haven't already, sign up for a free account now.

Once in your dashboard, you need to register your Laravel API with Auth0.

  • Click on "Applications" > "APIs" in the left sidebar.
  • Click the "Create API" button.
  • Enter a "Name" and "Identifier" for your API. You can name it anything you want.

Note: For Identifier, we recommend using a URL. This doesn't have to be a publicly available URL, and Auth0 will never call it.

  • Leave Signing Algorithm as is.
  • Click "Create".

Laravel Auth0 API

Keep this tab open, as you'll need to grab some values from it soon.

Install dependencies

Once you have your API set up, switch back to your terminal and run:

composer require auth0/login

This will install the Auth0 Laravel plugin.

Next, you need to generate the configuration file. To do this, run:

php artisan vendor:publish --provider "Auth0\Login\LoginServiceProvider"

This will generate a configuration file at config/laravel-auth0.php. Open it up now, and you should see these values interspersed throughout:

return [
  // ...
  'domain'        => env('AUTH0_DOMAIN'),
  'client_id'     => env('AUTH0_CLIENT_ID'),
  'client_secret' => env('AUTH0_CLIENT_SECRET'),
  'redirect_uri'  => env( 'APP_URL' ).'/auth0/callback',
  'authorized_issuers' => [ 'https://'.env('AUTH0_DOMAIN').'/' ],
  // 'api_identifier' => '',
  'supported_algs' => [ 'RS256' ],
  // ...
];

Find api_identifier, uncomment it, and replace it with:

'api_identifier' => env('API_IDENTIFIER'),

Finally, you need to update your .env file to include some of these values. Paste the following into .env.

AUTH0_DOMAIN=your-domain.auth0.com
API_IDENTIFIER=https://your-api.com
AUTH0_CLIENT_ID=

Now let's fill them in. Back in the Auth0 dashboard:

  • Go to the Laravel API you just registered
  • Click on the "Quick Start" tab
  • Click on "PHP"
  • You'll see two values there: valid_audiences and authorized_iss
  • Copy the value for valid_audiences and paste it in as the value for API_IDENTIFIER
  • Copy the value for authorized_iss and paste it in as the value for AUTH0_DOMAIN.
  • Click on the "Machine to machine applications" tab and find the Test Application that was created for your API. Copy the Client ID and paste it in as the value for AUTH0_CLIENT_ID.

ā— Important: Omit the https:// portion of for AUTH0_DOMAIN. For example, you'll paste in your-domain.auth0.com instead of https://your-domain.auth0.com.

Here is some clarification about what each of these .env values mapped to the config/laravel-auth0.php values do:

  • authorized_issuers ā€” An array of allowed token issuers, which is just your tenant URL
  • api_identifier ā€” The identifier for your API registered with Auth0
  • supported_algs ā€” The signing algorithm used by the API

Create the middleware

Next, you need to create a middleware that will check for the existence and validity of the bearer token when making a request to a private endpoint.

To create the middleware, run the following:

php artisan make:middleware CheckJWT

This will create a new file at app/Http/Middleware/CheckJWT.php. Open it up and replace it with the following:

<?php
// app/Http/Middleware/CheckJWT.php

namespace App\Http\Middleware;

use Auth0\Login\Contract\Auth0UserRepository;
use Auth0\SDK\Exception\CoreException;
use Auth0\SDK\Exception\InvalidTokenException;
use Closure;

class CheckJWT
{
  protected $userRepository;

  /**
    * CheckJWT constructor.
    *
    * @param Auth0UserRepository $userRepository
    */
  public function __construct(Auth0UserRepository $userRepository)
  {
    $this->userRepository = $userRepository;
  }

  /**
    * Handle an incoming request.
    *
    * @param  \Illuminate\Http\Request  $request
    * @param  \Closure  $next
    * @return mixed
    */
  public function handle($request, Closure $next)
  {
    $auth0 = app()->make('auth0');

    $accessToken = $request->bearerToken();
    try {
      $tokenInfo = $auth0->decodeJWT($accessToken);
      $user = $this->userRepository->getUserByDecodedJWT($tokenInfo);
      if (!$user) {
        return response()->json(["message" => "Unauthorized user"], 401);
      }

    } catch (InvalidTokenException $e) {
      return response()->json(["message" => $e->getMessage()], 401);
    } catch (CoreException $e) {
      return response()->json(["message" => $e->getMessage()], 401);
    }

    return $next($request);
  }
}

When a request is made to a private endpoint, the handle() method of this middleware will run. It grabs the bearer token from the request and passes it to the decodeJWT() function.

The decodeJWT() function will then attempt to decode and verify the token. If the token is valid, the Auth0JWTUser will be retrieved. Otherwise, an error is thrown.

Next, you need to register this middleware. Open up app/Http/Kernel.php and scroll down to the $routeMiddleware array. Add in the following to register the middleware:

protected $routeMiddleware = [
  // ...
  'jwt' => \App\Http\Middleware\CheckJWT::class,
  // ...
];

Apply middleware to routes

Finally, let's use this middleware to protect the API endpoints!

As a reminder, the goal is that the endpoints to get all comments and get a single comment remain public, while the rest require a token to access.

Open up routes/api.php. Currently, you have a single apiResource route doing everything, but you don't want to apply the middleware to every resource. To fix this, you can break them apart and then only apply middleware to the store, update, and destroy actions:

Route::resource('comments', CommentController::class)->only([
  'index', 'show'
]);

Route::resource('comments', CommentController::class)->only([
  'store', 'update', 'destroy'
])->middleware('jwt');

Testing your protected routes

Let's test it one more time to make sure that comments can't be created, updated, or destroyed without an access token.

But first, try to make a new comment from your command line without a token:

curl -X POST -H 'Content-Type: application/json' -d '{
  "name": "Lucy",
  "text": "An authorized comment"
}' http://localhost:8000/api/comments -i

This should return a 401 Unauthorized status code.

Now, let's try it again, but this time with an access token.

Back in the Auth0 dashboard, click on the Laravel API that you created earlier, and then click on the "Test" tab. Under "Response", you'll see an access token that has been generated for you to test your API.

Click the copy symbol to copy that token.

Modify the previous cURL command with the following, but make sure you first replace YOUR_ACCESS_TOKEN_HERE with the test token from your dashboard:

curl -X POST -H 'Authorization: Bearer YOUR_ACCESS_TOKEN_HERE' -H 'Content-Type: application/json' -d '{
    "name": "Lucy",
    "text": "An authorized comment"
}' http://localhost:8000/api/comments -i

The comment creation should now work! Feel free to test this with updating and deleting comments as well.

Now, if you want to protect any other routes in your API, all you need to do is add the jwt middleware!

Conclusion

And that's it! Just to recap, you've learned how to set up a Laravel API complete with the following:

  • SQLite database
  • Easy-to-run migrations
  • A seeder that uses Faker to create mock data
  • Authorization using Auth0

Please let me know if you have any questions in the comments below. Thanks for reading!

  • Twitter icon
  • LinkedIn icon
  • Faceboook icon