Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make JWT cookie authentication in Laravel

I want to have JWT authentication in Laravel >=5.2, using this (Tymon JWT-auth) library but I want to put JWT token into HttpOnly Cookies - to protect JWT token from steal from XSS attack.

  1. I set up Tymon library and... in project: app/Providers/RouteServiceProvider@mapWebRoutes i deactivate execution 'web' middelware group for all requests (which is default laravel behavior - you can see it by php artisan route:list) by remove 'middleware' => 'web' (If I don't do it, i will see CSRF problem with post request).
  2. in routes.php i write:
Route::group(['middleware' =>'api', 'prefix' => '/api/v1', 'namespace' => 'Api\V1'], function () {
    Route::post('/login', 'Auth\AuthController@postLogin');
    ...
    Route::get('/projects', 'ProjectsController@getProjects');
}
  1. In may Api\V1\Auth\AuthController@postLogin i generate token and send it back as httpOnly cookie:

    ...
    try
    {
        $user = User::where('email','=',$credentials['email'])->first();
    
        if ( !($user && Hash::check($credentials['password'], $user->password) ))
        {
            return response()->json(['error' => 'invalid_credentials'], 401);
        }
    
        $customClaims = ['sub' => $user->id, 'role'=> $user->role, 'csrf-token' => str_random(32) ];
        $payload = JWTFactory::make($customClaims);
        $token = JWTAuth::encode($payload);
    } catch(...) {...}
    return response()->json($payload->toArray())->withCookie('token', $token, config('jwt.ttl'), "/", null, false, true); 
    
  2. And, yeah here question starts. I would like to do something (may be modifiy laravel Auth class) on each request:

    • get coookie from request
    • decode it
    • check is right (if not trhow 401)
    • get user from DB
    • and make that method Auth::user() works every where like in usual way in laravel (so i can use it in each Controller for example)

Any ideas how to do point 4 ?

UPDATE

I also add here protection for CSRF attack - csrf-token is in JWT, and it is also return in body of response for login request (so JS have acces to this csrf-token) (i return only public part of JWT token in login response, whole JWT is return only in cookie, so it is XSS safe) - then front JS must copy csrf-token into header of each request. Then the middelware JWTAuthentiacate (in my answer below) compare csrf-token header with csrf-token field in JWT payload - if they are similar then request pass csrf test.

like image 901
Kamil Kiełczewski Avatar asked Jul 16 '16 21:07

Kamil Kiełczewski


1 Answers

You can do it simple by creating middleware.

In handle() method just get cookie from request, decode it and login a user using id with this Laravel method:

Auth::loginUsingId($userIdFromToken);
like image 127
Łukasz Kuczmaja Avatar answered Oct 27 '22 00:10

Łukasz Kuczmaja