tuupola / slim-jwt-auth

PSR-7 and PSR-15 JWT Authentication Middleware
https://appelsiini.net/projects/slim-jwt-auth
MIT License
821 stars 140 forks source link

How does the before/after parameter work? #253

Open NeftaliAcosta opened 3 months ago

NeftaliAcosta commented 3 months ago

I am using the plugin and I need to perform some validations after validating the token. In this sense, my app only allows a single login from devices, therefore, I validate that the token received is equal to the last token generated, if not, I should not accept requests and return a 401 message, however, My code does not work, since after performing the corresponding validations it continues with the flow without stopping after doing the validations.

Can you help me, please? Thank you so much.

` return function (App $app) { $key = $_ENV['JWT_AUTH_KEY']; $app->add(SessionMiddleware::class);

$app->add(
    new Tuupola\Middleware\JwtAuthentication([
        "header" => "Authorization",
        "attribute" => "jwt",
        "secure" => true,
        "path" => "/",
        "ignore" => [
            "/auth/validate",
            "/auth/recovery-password",
            "/auth/reset-password",
            "[/]"
        ],
        "secret" => $key,
        "before" => function ($request, $arguments) {
            // Get values requires
            $token = $request->getHeaders('Accept')['Authorization'][0];
            $token = str_replace('Bearer ', '', $token);
            try {
                // Instance User object
                $oUser = new Users();
                $ssid = json_decode($oUser->getSsid());
                if (
                    $ssid->jwt !== $token) {
                    // this code does not work
                    $response = new Response();
                    $response = $response->withStatus(401);
                    $response->getBody()->write('Unauthorized');
                    return $response;
                }
            } catch (UserNotFoundException $e) {
                // this code does not work
                $response = new Response();
                $response = $response->withStatus(401);
                $response->getBody()->write('Unauthorized');
                return $response;
            }

            return true;
        },
        "error" => function ($response, $arguments) {
            $data["statusCode"] = $response->getStatusCode();
            $data["message"] = ["Exception" => [$arguments["message"]]];
            $data["data"] = [];

            $response->getBody()->write(
                json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)
            );

            return $response->withHeader("Content-Type", "application/json");
        }
    ])
);

}; `

Update:

I have updated my code like this, and it partially works, it already returns the response I want, but I cannot stop the flow and it also returns the response from the endpoint I am accessing:

` return function (App $app) { $key = $_ENV['JWT_AUTH_KEY']; $app->add(SessionMiddleware::class);

$app->add(
    new Tuupola\Middleware\JwtAuthentication([
        "header" => "Authorization",
        "attribute" => "jwt",
        "secure" => true,
        "path" => "/",
        "ignore" => [
            "/auth/validate",
            "/auth/recovery-password",
            "/auth/reset-password",
            "users/",
            "/dictionary",
            "[/]"
        ],
        "secret" => $key,
        "after" => function (Response $response, $arguments) {
            // Get values requires
            $token = $arguments['token'];
            $uuid = $arguments['decoded']['uuid'];
            // Instance User object
            $oUser = new Users();
            $id = $oUser->getIdFromUuid($uuid);
            $oUser = new Users($id);
            $ssid = json_decode($oUser->getSsid());
            if (
                $ssid->jwt !== $token ||
                $ssid->sid !== $arguments['decoded']['sid'] ||
                $ssid->uuid !== $arguments['decoded']['uuid']
            ) {
                $data["statusCode"] = 401;
                $data["message"] = ["Exception" => ["Token not valid for this session."]];
                $data["data"] = [];
                $response = $response->withStatus(401);
                $response->getBody()->write(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
                return false;
            }
        },
        "error" => function ($response, $arguments) {
            $data["statusCode"] = $response->getStatusCode();
            $data["message"] = ["Exception" => [$arguments["message"]]];
            $data["data"] = [];

            $response->getBody()->write(
                json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)
            );

            return $response->withHeader("Content-Type", "application/json");
        }
    ])
);

};

`

Response:

image

JimTools commented 3 months ago

@NeftaliAcosta having the middleware also try and handle error logic isn’t ideal. The ‘after’ option is designed to modify the response which gets passed to the next middleware.

A better way of doing is by throwing a custom exception and handle this in your error handling.

better yet just write a custom middleware with this logic.