title: Build a JWT Authenticated API with Lumen(v5.8) published: true description: In this tutorial, we will be using lumen; a super-fast micro-framework by laravel to build a simple and secure REST API. At the end of this tutorial, you should be able to build production-ready APIs. Let's get started! tags: php,lumen,laravel,webDev canonical_url: https://voidnerd.com/posts/build-a-jwt-authenticated-api-with-lumen


In this tutorial, we will be using lumen; a super-fast micro-framework by laravel to build a simple and secure REST API. At the end of this tutorial, you should be able to build production-ready APIs. Let's get started!

Prerequisite

Make sure you have the essentials, I beg of you.

  • PHP >= 7.1.3
  • OpenSSL PHP Extension
  • PDO PHP Extension
  • Mbstring PHP Extension
  • Mysql >= 5.7
  • Composer (Dependency Manager for PHP)
  • Postman (To test your endpoints)

Installation

First things first, you need to get lumen's cli.

$ composer global require "laravel/lumen-installer"

If your download was successful, run below command to confirm you have lumen installed.

$ lumen If you encounter an error like -bash: lumen: command not found, you need to add composer's vender bin to your path.

If all is in order, you should see something like so.

Lumen

Now run this command to create the lumen project

$ lumen new auth-app

Enter the project folder $ cd auth-app

Run the app $ php -S localhost:8000 -t public Load localhost:8000 on your browsers address bar and it should render a result as shown below.

Lumen response

Open up the project (auth-app) in your preferred editor.

Create a .env file, copy all contents in .env.example into the .env file and add your database configurations.

In boostrap/app.php uncomment the facades and eloquent method

```php //before

// $app->withFacades();

// $app->withEloquent();

//after

$app->withFacades();

$app->withEloquent();

``` Turning on withFacades inject the application IoC to Illuminate\Support\Facades\Facade. Without doing so even if you're importing Illuminate\Support\Facades\File it wouldn't work. Credit

The $app->withEloquent() method actually enables the query builder too. It's registering the DatabaseServiceProvider, which is required to use the query builder. Credit.

Create a user

Make user's database migration

$ php artisan make:migration create_users_table --create=users

Locate the migration file database/migrations/*_create_users_table.php and add neede table columns(name, email, password); see code below:

php ... public function up() { Schema::create('users', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name'); $table->string('email')->unique()->notNullable(); $table->string('password'); $table->timestamps(); }); } ...

Migrate your database

``` $ php artisan migrate

```

Add register route which as the name implies; register users. Locate routes/web.php and insert the needed code as seen below

```php // API route group $router->group(['prefix' => 'api'], function () use ($router) { // Matches "/api/register $router->post('register', 'AuthController@register');

}); ```

Since we are going to prefix api in all our endpoint, to reduce repetition we will use route grouping to do just that.

This method ($router->post($uri, $callback); takes in a $url and a $callback parameter. In the $callback, AuthController is our controller class (we will create this class in a bit) and register is a method in said class.

Let's create our AuthControler.

Create file app/Http/Controllers/AuthController.php and populate it with code as seen below.

```php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request; use App\User;

class AuthController extends Controller { /* * Store a new user. * * @param Request $request * @return Response / public function register(Request $request) { //validate incoming request $this->validate($request, [ 'name' => 'required|string', 'email' => 'required|email|unique:users', 'password' => 'required|confirmed', ]);

    try {

        $user = new User;
        $user->name = $request->input('name');
        $user->email = $request->input('email');
        $plainPassword = $request->input('password');
        $user->password = app('hash')->make($plainPassword);

        $user->save();

        //return successful response
        return response()->json(['user' => $user, 'message' => 'CREATED'], 201);

    } catch (\Exception $e) {
        //return error message
        return response()->json(['message' => 'User Registration Failed!'], 409);
    }

}

} ```

Register a user(use POSTMAN) with route localhost:8000/api/register and you should get a successful response like so

Lumen register example

User sign in

Pull in the JWT authentication package.

$ composer require tymon/jwt-auth:dev-develop

Generate your API secret

$ php artisan jwt:secret

create file config/auth.php with below config

```php //config.auth.php

<?php

return [ 'defaults' => [ 'guard' => 'api', 'passwords' => 'users', ],

'guards' => [
    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],

'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => \App\User::class
    ]
]

];

`` Make some changes to yourUsermodel(app/User.php`) to fit tymon/jwt-auth's requirements. Keep your eye out for everything that includes "JWT".

```php <?php

namespace App;

use Illuminate\Auth\Authenticatable; use Laravel\Lumen\Auth\Authorizable; use Illuminate\Database\Eloquent\Model; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;

use Tymon\JWTAuth\Contracts\JWTSubject;

class User extends Model implements AuthenticatableContract, AuthorizableContract, JWTSubject { use Authenticatable, Authorizable;

/**
 * The attributes that are mass assignable.
 *
 * @var array
 */
protected $fillable = [
    'name', 'email'
];

/**
 * The attributes excluded from the model's JSON form.
 *
 * @var array
 */
protected $hidden = [
    'password',
];




/**
 * Get the identifier that will be stored in the subject claim of the JWT.
 *
 * @return mixed
 */
public function getJWTIdentifier()
{
    return $this->getKey();
}

/**
 * Return a key value array, containing any custom claims to be added to the JWT.
 *
 * @return array
 */
public function getJWTCustomClaims()
{
    return [];
}

}

`` Make some changes tobootstrap/app.php`

```php //before // $app->routeMiddleware([ // 'auth' => App\Http\Middleware\Authenticate::class, // ]);

//After $app->routeMiddleware([ 'auth' => App\Http\Middleware\Authenticate::class, ]); ```

```php //before // $app->register(App\Providers\AppServiceProvider::class); // $app->register(App\Providers\AuthServiceProvider::class); // $app->register(App\Providers\EventServiceProvider::class);

//After // $app->register(App\Providers\AppServiceProvider::class); $app->register(App\Providers\AuthServiceProvider::class); // $app->register(App\Providers\EventServiceProvider::class);

// Add this line $app->register(Tymon\JWTAuth\Providers\LumenServiceProvider::class); ```

Add login route in routes/web.php

```php // API route group $router->group(['prefix' => 'api'], function () use ($router) { // Matches "/api/register $router->post('register', 'AuthController@register');

  // Matches "/api/login
 $router->post('login', 'AuthController@login');

}); ```

Add a global respondWithToken method to Controller class in app/Http/Controllers/Controller.php. This is so we could access it from any other controller.

```php ... //import auth facades use Illuminate\Support\Facades\Auth;

//Add this method to the Controller class protected function respondWithToken($token) { return response()->json([ 'token' => $token, 'token_type' => 'bearer', 'expires_in' => Auth::factory()->getTTL() * 60 ], 200); }

```

Add a login method to your AuthController class in app/Http/Controllers/AuthController.php

```php ...

//import auth facades use Illuminate\Support\Facades\Auth;

...

 /**
 * Get a JWT via given credentials.
 *
 * @param  Request  $request
 * @return Response
 */
public function login(Request $request)
{
      //validate incoming request 
    $this->validate($request, [
        'email' => 'required|string',
        'password' => 'required|string',
    ]);

    $credentials = $request->only(['email', 'password']);

    if (! $token = Auth::attempt($credentials)) {
        return response()->json(['message' => 'Unauthorized'], 401);
    }

    return $this->respondWithToken($token);
}

```

Login a user using route localhost:8000/api/login and you should get a successful response like so:

Lumen login example

Authenticated routes

For our grand finale, we are going to make some authenticated routes.

Add a couple of routes to routes/web.php

```php ... // API route group $router->group(['prefix' => 'api'], function () use ($router) { // Matches "/api/register $router->post('register', 'AuthController@register'); // Matches "/api/login $router->post('login', 'AuthController@login');

// Matches "/api/profile
$router->get('profile', 'UserController@profile');

// Matches "/api/users/1 
//get one user by id
$router->get('users/{id}', 'UserController@singleUser');

// Matches "/api/users
$router->get('users', 'UserController@allUsers');

});

...

```

Create a file app/Http/Controllers/UserController.php and populate it with this elegant looking code.

```php <?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Auth; use App\User;

class UserController extends Controller { /* * Instantiate a new UserController instance. * * @return void / public function __construct() { $this->middleware('auth'); }

/**
 * Get the authenticated User.
 *
 * @return Response
 */
public function profile()
{
    return response()->json(['user' => Auth::user()], 200);
}

/**
 * Get all User.
 *
 * @return Response
 */
public function allUsers()
{
     return response()->json(['users' =>  User::all()], 200);
}

/**
 * Get one user.
 *
 * @return Response
 */
public function singleUser($id)
{
    try {
        $user = User::findOrFail($id);

        return response()->json(['user' => $user], 200);

    } catch (\Exception $e) {

        return response()->json(['message' => 'user not found!'], 404);
    }

}

}

```

Below is an example call to one of the three newly added endpoints

Lumen users example

Here's a link to the full code on github.

The end-ish!

I hope this article has helped you in some way, and that you build upon this knowledge to deploy awesome APIs in the nearest future. I would like to see your contributions down in the comments too.

Hasta la vista.