Setup JWT for Laravel Lumen and AngularJS

So Laravel rewarded me for being an early adopter of their Micro-Framework Lumen by stripping it of Session and Cookie functionality, forcing me to rewrite code for several sites to use JWT authentication.

If you find yourself in the same spot, below is how is how I added JWT auth, of course in a very basic form as each site I am responsible for has custom integration.

JWT Front End Code

Using Satellizerhttps://github.com/sahat/satellizer for AngularJS, the setup was pretty simple:


//APP 
angular.module("app", ['satellizer','restangular']);

//CONFIG
angular.module("app").config(function($authProvider) {
    
    //PUTS TOKEN IN HEADER REQUESTS
    $authProvider.httpInterceptor = function() { return true; };
    //NAME YOUR TOKEN
    $authProvider.tokenPrefix = 'appToken';

});

//APP CONTROLLER
angular.module("app").controller('appCtrl', function($scope, $window, $rootScope, $auth, af) {

  //KEEP AUTH STATE IN SCOPE
  $scope.isAuth = false;

  //CREATE SIMPLE FUNCTION TO CHECK AUTH STATE
  $scope.isAuthenticated = function() {
    return $auth.isAuthenticated();
  };

  //SET AUTH STATE ON LOAD OF CONTROLLER
  $scope.isAuth = $scope.isAuthenticated();
});

//LOGIN
angular.module("app").controller('loginCtrl', function($scope, $window, $rootScope, $auth, af) {
  $scope.un = null;
  $scope.pw = null;

  $scope.loginSubmit = function()
  {
    if ($scope.loginForm.$valid)
    {
      var data = {};
      data.un = $scope.un; //USERNAME
      data.pw = $scope.pw; //PASSWORD
      var send = angular.toJson(data);

      //CALL RESTANGULAR METHOD FOR LOGIN
      return af.loginUser(data).then( function(d) {
              
              //SUCCESS
              if (d.return=='success')
              {
                $auth.setToken(d.token); //GET TOKEN FROM RESPONSE
                $window.location = '/'; //SET DESTINATION AFTER LOGIN
              }
              else { 
                 //HANDLE ERROR 
              }
             return d;
      });
    }
  }

//LOGOUT
angular.module("app").controller('logoutCtrl', function($scope, $window, $rootScope, $auth) {

    //SIMPLE LOGOUT AND REDIRECT
    //YOU MAY WANT TO WRAP THIS WITH LOGIC
    //TO CHECK IF LOGGED IN OR OTHER CRITERIA
    $auth.logout();
    $window.location = "/"; //REDIRECT TO HOMEPAGE
});

Update .htaccess

You may or may not have to do this, I did, so I am including it for you. This enables the “Bearer” JWT authentication token to pass through in each request.

    #ADDED THESE TWO LINES TO MAKE JWT TOKENS WORK WITH LUMEN
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]    

    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]

Setup JWT Backend

Using composer I installed the PHP-JWThttps://github.com/firebase/php-jwt library.

Here is example code in the controller to check, parse, encode and decode JWT tokens.

namespace App\Http\Controllers;
use Illuminate\Http\Response;
use Illuminate\Http\Request;
use \Firebase\JWT\JWT;

use Laravel\Lumen\Routing\Controller as BaseController;

class YourController extends BaseController
{
    //CREATED SOME PROTECTED VARS
    protected $raw_token;
    protected $token_key;
    protected $decoded_token;

    //PARSE REQUEST BEFORE ADVANCING 
    function __construct(Request $r)
    {
      //GET JWT KEY SET IN THE .ENV FILE
      $this->token_key = $_ENV['JWT_KEY'];

      //CHECK THAT AUTHORIZATION INCLUDED
      //IN HEADER REQUEST
      if(null !== $r->header('authorization'))
      {
        //GET AUTHORIZATION PORTION
        $h = $r->header('authorization');

        //BREAK IT IN TWO
        $t = explode(" ",$h);

        //GET RAW JWT TOKEN
        $this->raw_token = $t[1];

        //SET DECODED TOKEN
        $this->decoded_token = JWT::decode($this->raw_token,$this->token_key,array('HS256'));

      }
      else {
        //RETURN ERROR RESPONSE OR REDIRECT
        //NOTE, MUST USE '->send()' OR THIS REQUEST
        //WILL PROCEED TO ROUTED FUNCTION
        return response()->json('error')->send();
      }
    }

    //FUNCTION TO LOGIN USER CALLED FROM FRONT END RESTANGULAR 
    //AND ROUTED HERE VIA THE ROUTES.PHP FILE
    function loginMyUser(Request $r)
    {
       //CHECK USER LOGIN REQUEST LOGIC
       if ($r->un && $r->pw)
       {
            $someVar = array(); //SET DATA YOU NEED ON THE FRONT END
            return response()->json(array('token'=>$this->setToken($someVar)));
       }
    }

    //INTERNAL FUNCTION TO SET TOKEN
    function setToken($someVar)
    {
      //GET JWT KEY SET IN .ENV FILE
      $JWT_KEY = $_ENV['JWT_KEY'];

      //CREATE ARRAY FOR JWT TOKEN
      $token = array(
          "iss" => "http://yoursite.com", //SET DOMAIN
          "aud" => "http://yoursite.com", //SET DOMAIN
          "iat" => strtotime("now"), //SET ACTIVATED TIME
          "exp" => strtotime("+ 1 week"), //SET EXPIRED TIME
          "public" => array("this"=>"can be easily decoded because it is stored as base64"),
          "private" => $this->encrypt($someVar) //SET ENCODED VALUES USING CUSTOM ENCRYPTION
      );
      $jwt = JWT::encode($token, $JWT_KEY);
      return $jwt;
    }

Final Thoughts

If you need help or have questions please post them below, this took a bit of time to figure out, but once I did it was pretty easy simplify and replicate.

HTH

😉

one comment ( awaiting your reply! )

  • Hello.
    I have one question, how do you tell Lumen to use the Controller for handling the login?

    -- anmaur