How integrate jwt with the 4th version of Slim

First you import Tuupola jwt library.

$ cd my-api-project
$ composer require tuupola/slim-jwt-auth

Then create the .htaccess file inside the public/ folder with the following code.

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

After that you must create your controller for user authentication.

<?php

namespace App\Controllers;

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;

use App\Models\Users;
use Firebase\JWT\JWT;
use App\Utilities\JsonRenderer;

final class Auth
{
    private JsonRenderer $renderer;
    private Users $Users;

    public function __construct(JsonRenderer $renderer, Users $Users)
    {
        $this->renderer = $renderer;
        $this->Users = $Users;
    }

    public function __invoke(Request $req, Response $res): Response
    {
        try {
            if ($req->hasHeader("email") && $req->hasHeader("senha")) :
                $result = $this->Users->getUserByEmail($req->getHeader("email")[0]);

                if (!isset($result["Error"])) :

                    if (!is_null($result)) :

                        if ($req->getHeader("senha")[0] === $result["senha"]) :

                            $expire = (new \DateTime("now", new \DateTimeZone("America/Sao_Paulo")))->modify("+1 hour")->format("Y-m-d H:i:s");
                            $token = JWT::encode(["expired_at" => $expire], "I3SISTEMAS");

                            return $this->renderer->json($res, [
                                "Success" => [
                                    "token" => $token
                                ]
                            ])->withHeader("Content-Type", "application/json")
                                ->withStatus(201);
                        else :
                            return $this->renderer->json($res, [
                                "Error" => [
                                    "Message" => "Falha Na Autenticação"
                                ]
                            ])->withHeader("Content-Type", "application/json")
                                ->withStatus(401);
                        endif;
                    else :
                        return $this->renderer->json($res, [
                            "Error" => [
                                "Message" => "Falha Na Autenticação"
                            ]
                        ])->withHeader("Content-Type", "application/json")
                            ->withStatus(401);
                    endif;
                else :
                    return $this->renderer->json($res, [
                        "Error" => [
                            "Message" => $result["Error"]
                        ]
                    ])->withHeader("Content-Type", "application/json")
                        ->withStatus(500);
                endif;
            else :
                return $this->renderer->json($res, [
                    "Error" => [
                        "Message" => "Você Deve Passar o `email` && `senha` no Cabeçalho!"
                    ]
                ])->withHeader("Content-Type", "application/json")
                    ->withStatus(422);
            endif;
        } catch (\PDOException $e) {
            return $this->renderer->json($res, [
                "Error" => [
                    "Message" => $e->getMessage()
                ]
            ])->withHeader("Content-Type", "application/json")
                ->withStatus(500);
        }
    }
}

Next, create the authentication route.

$app->post("/auth", \App\Controllers\Auth::class);

Remembering that this is my method of verifying and authenticating a user, in your case it may be different.

Leaving this controller aside, let’s create the middleware that will check if the token passed in the “Authorization” header is valid.

In this case you must create a middleware folder, then create the jwtAuth.php file and put the following code.

<?php

namespace App\Middlewares;

use Nyholm\Psr7\Response as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;

use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use App\Utilities\JsonRenderer;

final class jwtAuth
{
    private JsonRenderer $renderer;
    private Response $res;

    public function __construct(JsonRenderer $renderer, Response $res)
    {
        $this->renderer = $renderer;
        $this->res = $res;
    }

    public function __invoke(Request $req, RequestHandler $han)
    {
        try {
            if ($req->hasHeader("Authorization")) :
                $header = $req->getHeader("Authorization");

                if (!empty($header)) :
                    $bearer = trim($header[0]);
                    preg_match("/Bearer\s(\S+)/", $bearer, $matches);
                    $token = $matches[1];

                    $key = new Key("I3SISTEMAS", "HS256");
                    $dataToken = JWT::decode($token, $key);
                    $now = (new \DateTime("now", new \DateTimeZone("America/Sao_Paulo")))->format("Y-m-d H:i:s");

                    if ($dataToken->expired_at < $now) :
                        return $this->renderer->json($this->res, [
                            "Error" => [
                                "Message" => "Token Expirado!"
                            ]
                        ])->withHeader("Content-Type", "application/json")
                            ->withStatus(401);
                    endif;
                endif;
            else :
                return $this->renderer->json($this->res, [
                    "Error" => [
                        "Message" => "Acesso Não Autorizado!"
                    ]
                ])->withHeader("Content-Type", "application/json")
                    ->withStatus(401);
            endif;
        } catch (\Exception $e) {
            return $this->renderer->json($this->res, [
                "Error" => [
                    "Message" => $e->getMessage()
                ]
            ])->withHeader("Content-Type", "application/json")
                ->withStatus(500);
        }
        $res = $han->handle($req);
        return $res;
    }
}

After that we should import the middleware/jwtAuth.php in the routes file.

use App\Middlewares\jwtAuth;

Then add the class like any other controller.

->add(jwtAuth::class);

Example

$app->get("/", \App\Controllers\HomeAction::class)->add(jwtAuth::class);

For those who want to use the “JsonRenderer” method that I use, they must create a folder called Utilities, after that, inside the folder, create the JsonRenderer.php file, and add the following code:

<?php

namespace App\Utilities;

use Psr\Http\Message\ResponseInterface;

final class JsonRenderer
{
    public function json(ResponseInterface $res, $data = null, int $options = 0): ResponseInterface
    {
        $res = $res->withHeader("Content-Type", "application/json");
        $res->getBody()->write((string)json_encode($data, $options));

        return $res;
    }
}

Remembering that you must pass the token in the “Authorization” header otherwise the application will not allow access to the designated routes.

In theory everything is ready, if you have a problem, you can send it down here.
Another thing, I’m not AMERICAN, I had to use a translator, in case the words are a bit meaningless, don’t blame me, blame google Translate :slight_smile:

I hope I helped you, a hug to all of you :slight_smile: