Securing Laravel APIs using JWT

About Me

Md. Shahbaz Alam

Full Stack Developer

Auth0 Ambassador

Mozilla Reps Mentor

GDG Ranchi Organizer

 

@mdsbzalam

 

Agenda

1. Authentication & Authorization

2. JWT

3. Securing Laravel API

4. Demo

Authentication & Authorization

Authentication & Authorization

Difference

Difference

Authentication & Authorization

Authentication & Authorization

source: dadario.com.br

Authentication & Authorization

source: dadario.com.br

JSON Web Token

JWT

What is JSON Web Tokens?

- A way to encode information

- Securely communicate JSON Objects

- Secret-based Verification

- Consists of a header, payload and signature

- Self-contained

JWT

JSON Web Token

JWT

The JWT Header

The header is a JSON Object usually consisting of the type( typ ) , which is JWT, and the algorithm used for encrypting the JWT (alg ):

{
  "alg": "HS256",
  "typ": "JWT"
}

JWT

The JWT Payload

The Payload is a JSON object that consists of user defined attributes ( called public claims ) . Some attributes are defined in the standard ( these are called reserved claims ).

{
    // reserved claim
    "iss": "https://myapi.com", 
    // public claim
    "user": "mdsbzalam" 
}

JWT

The JWT Signature

The Signature is the encoded header and payload, signed with a secret.

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret
)

This accomplishes several tasks at once, including:

  • Proves the identity of the sender
  • Ensures the message has not changed

JWT

The JWT Token

A finished token looks like [encoded header].[encoded payload].[signature] :

JWT

The JWT Token

How an application uses JWT to verify the authenticity of a user.

Securing Laravel API

  • GET /api/public: available for non-authenticated requests

 

  • GET /api/private: available for authenticated requests containing an Access Token

API endpoint

Validate Access Tokens

* Install dependencies

Protecting Laravel API requires a middleware which will check for and verify an Access Token in the Authorization header of an incoming HTTP request.

composer require auth0/login:"~5.0"

we use the middleware provided in the laravel-auth0 package.

Install laravel-auth0 using Composer.

Validate Access Tokens

* Enable the provider

The laravel-auth0 package comes with a provider called LoginServiceProvider.

Add this to the list of application providers.

// config/app.php

'providers' => [
    // ...
     \Auth0\Login\LoginServiceProvider::class,

],

Validate Access Tokens

* Enable the provider

If you would like to use the Auth0 facade, add it to the list of aliases.

// config/app.php

 'aliases' => [
    // ...
    'Auth0' => \Auth0\Login\Facade\Auth0::class,
],

We will now be able to access user info with Auth0::getUser().

Validate Access Tokens

* Enable the provider

Finally, we need to bind a class that provides a user each time the user is logged in or an Access Token is decoded.

You can use the Auth0UserRepository provided by laravel-auth0 package.

Validate Access Tokens

* Enable the provider

To use Auth0UserRepository, add the following lines to your AppServiceProvider:

// app/Providers/AppServiceProvider.php

public function register()
{

    $this->app->bind(
        \Auth0\Login\Contract\Auth0UserRepository::class,
        \Auth0\Login\Repository\Auth0UserRepository::class
    );

}

Validate Access Tokens

* Configure the plugin

The laravel-auth0 plugin comes with a configuration file that can be generated using artisan. Generate the file and complete the details found within.

php artisan vendor:publish

After the file is generated, it will be located at config/laravel-auth0.php.

Validate Access Tokens

* Define a User and User Provider

We need to configure the driver in config/auth.php to use auth0 as Authentication Provider.

// config/auth.php

// ...
'providers' => [
    'users' => [
        'driver' => 'auth0'
    ],
],

The default provider is Eloquent, which persists the User model in a database using the ORM.

Validate Access Tokens

* Protect API Endpoints

Define a middleware to check and verify Access Token in the Authorization header of an incoming HTTP request.

php artisan make:middleware CheckJWT
// /app/Http/Middleware/CheckJWT.php
....
class CheckJWT
{
    protected $userRepository;

    public function __construct(Auth0UserRepository $userRepository)
    {
        $this->userRepository = $userRepository;
    }

    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);
            }

            \Auth::login($user);

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

        return $next($request);
    }
}

Validate Access Tokens

* Protect API Endpoints

To Assign the middleware to specific routes, append it to the list and assign a key in $routeMiddleware property.

// /app/Http/Kernel.php

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

* Protect API Endpoints

Protecting individual API endpoints can be done by applying the jwt middleware to them.

// routes/api.php

// This endpoint doesn't need authentication
Route::get('/public', function (Request $request) {
    return response()->json([
         "conference" => "Welcome to Laravel Live IN.",
         "token" => "not required", 
         "message" => "You don't need to be authenticated to see this."
        ]);
});

Route::get('/private', function (Request $request) {
    return response()->json([
         "conference" => "Welcome to Laravel Live IN.",
         "token" => "required", 
         "message" => "You need to have a valid Access Token to see this."
        ]);
})->middleware('jwt');

This route is now only accessible if an Access Token is included in the Authorization header of the incoming request.

source: auth0.com

* Configure Auth0 APIs

Token Expiration in seconds.

Demo

/api/public

{
    "message": "Hello from a public endpoint! 
                    You don't need to be authenticated to see this.",
    "conference": "Laravel Live IN"
}

/api/private

{
    "message": "Hello from a private endpoint! 
                    You need to have a valid access token to see this.",
    "conference": "Laravel Live IN",
    "talk": "Securing Laravel APIs using JWT",
    "follow me": {
        "twitter": "@mdsbzalam",
        "facebook": "mdsbzalam",
        "linkedin": "in/mdsbzalam",
        "email": "mdsbzalam@gmail.com"
    }
}

Resources

General JWT Resources

jwt.io 

JWT Handbook

http://bit.ly/jwt-book

Laravel API Authentication & Authorization

https://auth0.com/docs/quickstart/backend/laravel

Connect with me

Facebook

facebook.com/mdsbzalam

Twitter

@mdsbzalam

Instagram

@mdsbzalam

LinkedIn

https://in.linkedin.com/in/mdsbzalam

E-mail

mdsbzalam@gmail.com

Slide

Thank you

@mdsbzalam

Laravel Live India 2019

By Mohammad Shahbaz Alam

Laravel Live India 2019

Securing Laravel APIs using JWT

  • 1,140