Skip to content

Slim3 Framework Authorization with JWT (JSON Web Tokens)

Last updated on June 11, 2018

In this post, I will show how you can secure your Slim3 Framework-based applications using JSON Web Token (JWT). To know more about JWT and How it works visit the official website(https://jwt.io).

Download & Install

We gonna use composer to download and install the Slim Framework. The easiest way to start working with Slim is to create a project using Slim-Skeleton as a base by running this bash command:


$ php composer.phar create-project slim/slim-skeleton [my-app-name]

Replace [my-app-name] with the desired directory name for your new application.

You can then run it with PHP’s built-in web server:


$ cd [my-app-name]; php -S localhost:8080 -t public public/index.php

While running built-in web server you can access the application at: http://localhost:8080. If you head over to the browser with this URL you should get following output:

Connect to database

We gonna use MySQL as a database engine, so lets open src/settings.php file and add follwing array to settings array.

        // database connection details         
        "db" => [            
             "host" => "your-host",             
             "dbname" => "your-database-name",             
             "user" => "your-db-username",            
             "pass" => "your-db-password"        
         ],

After placing your database settings, lets open src/dependencies.php file and inject database object into container with following code:


// PDO database library 
$container['db'] = function ($c) {
    $settings = $c->get('settings')['db'];
    $pdo = new PDO("mysql:host=" . $settings['host'] . ";dbname=" . $settings['dbname'],
        $settings['user'], $settings['pass']);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
    return $pdo;
};

Now you can access this database connection instance with $this->db.

JWT Authentication

We gonna use tuupola/slim-jwt-auth library to handle JWT tokens. So let install it with composer, fire up the terminal and change the directory to project root and issue following composer command


$ composer require tuupola/slim-jwt-auth

After installation, open the src/settings.php file and append the followign JWT setttings array to existing settings array.


        // jwt settings
        "jwt" => [
            'secret' => 'supersecretkeyyoushouldnotcommittogithub'
        ]

That’s it.

Now open your src/middleware.php file and add following code.

add(new \Slim\Csrf\Guard);
$app->add(new \Tuupola\Middleware\JwtAuthentication([
    "path" => "/api", /* or ["/api", "/admin"] */
    "attribute" => "decoded_token_data",
    "secret" => "supersecretkeyyoushouldnotcommittogithub",
    "algorithm" => ["HS256"],
    "error" => function ($response, $arguments) {
        $data["status"] = "error";
        $data["message"] = $arguments["message"];
        return $response
            ->withHeader("Content-Type", "application/json")
            ->write(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
    }
]));

We have configured the middleware to auth check only the URLs contains the /api. If you want to pass multiple patterns pass them in an array format.

Open your src/routes.php file and define new route for login as shown below –

...
use Slim\Http\Request;
use Slim\Http\Response;
use \Firebase\JWT\JWT;

.......
....
$app->post('/login', function (Request $request, Response $response, array $args) {

    $input = $request->getParsedBody();
    $sql = "SELECT * FROM users WHERE email= :email";
    $sth = $this->db->prepare($sql);
    $sth->bindParam("email", $input['email']);
    $sth->execute();
    $user = $sth->fetchObject();

    // verify email address.
    if(!$user) {
        return $this->response->withJson(['error' => true, 'message' => 'These credentials do not match our records.']);  
    }

    // verify password.
    if (!password_verify($input['password'],$user->password)) {
        return $this->response->withJson(['error' => true, 'message' => 'These credentials do not match our records.']);  
    }

    $settings = $this->get('settings'); // get settings array.
    
    $token = JWT::encode(['id' => $user->id, 'email' => $user->email], $settings['jwt']['secret'], "HS256");

    return $this->response->withJson(['token' => $token]);

});

On the successful login, it will return JWT token. This method is pretty straightforward, first, we are validating the user with email and password, if the request is valid we are generating the JWT auth token. The user has to send this token in the header(Authorization: Bearer ) in order to get access to the protected routes/URLs.

Let’s define another route, it’s not public route, you need to send Authorization token to get access to it. As I mentioned above this URL is staring with /api so the user must authenticate to access this page.


$app->group('/api', function(\Slim\App $app) {

    $app->get('/user',function(Request $request, Response $response, array $args) {
        print_r($request->getAttribute('decoded_token_data'));

        /*output 
        stdClass Object
            (
                [id] => 2
                [email] => [email protected]
            )
                    
        */
    });
   
});

My user table structure and its sample data:



CREATE TABLE `users` (
  `id` int(10) UNSIGNED NOT NULL,
  `first_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `last_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT '2019-01-25 22:11:50',
  `updated_at` timestamp NOT NULL DEFAULT '2019-01-25 22:11:50'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

INSERT INTO `users` (`id`, `first_name`, `last_name`, `email`, `password`, `created_at`, `updated_at`) VALUES
(2, 'Arjun', 'A', '[email protected]', '$2y$10$2N74YBkxYXPtEtFTxynuxeEn9OH9BZ.wI4ldZr00n1FX5q09/llbO', '2018-02-22 18:30:00', '2018-02-22 18:30:00');

ALTER TABLE `users`
  ADD PRIMARY KEY (`id`),
  ADD UNIQUE KEY `users_email_unique` (`email`);

ALTER TABLE `users`
  MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;

How to deploy slim framework on CPanel

Note: Here my encrypted password is Arjun@123

How to test

We gonna use Adanced RESt client to test apis, below are the screen shot of it.

3 1 vote
Article Rating
Subscribe
Notify of
guest

91 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments