phpcodeigniter-4php-jwt

Invalid token and 'Failed to parse json string'


I am creating a REST API using CI4. I want to create a auth filter and ran into a problem.

When token is valid or not send, everything is fine.

Problem is when I change the content of token before sending (add or remove a character) then instead of getting response that is in catch I have this in Chrome console:

GET https://api.***/admin/users 500

<br />
<b>Fatal error</b>:  Uncaught CodeIgniter\Format\Exceptions\FormatException: Failed to parse json string, error: &quot;Malformed UTF-8 characters, possibly incorrectly encoded&quot;. in /home/mma/domains/***/ci4/vendor/codeigniter4/framework/system/Format/JSONFormatter.php:41
Stack trace:
#0 /home/mma/domains/***/ci4/vendor/codeigniter4/framework/system/Format/JSONFormatter.php(41): CodeIgniter\Format\Exceptions\FormatException::forInvalidJSON('Malformed UTF-8...')
#1 /home/mma/domains/***/ci4/vendor/codeigniter4/framework/system/API/ResponseTrait.php(341): CodeIgniter\Format\JSONFormatter-&gt;format(Array)
#2 /home/mma/domains/***/ci4/vendor/codeigniter4/framework/system/API/ResponseTrait.php(99): CodeIgniter\Debug\Exceptions-&gt;format(Array)
#3 /home/mma/domains/***/ci4/vendor/codeigniter4/framework/system/Debug/Exceptions.php(115): CodeIgniter\Debug\Exceptions-&gt;respond(Array, 500)
#4 [internal function]: CodeIgniter\Debug\Exceptions-&gt;exceptionHandler(Object(DomainException))
#5 in <b>/home/mma/domains/***/ci4/vendor/codeigniter4/framework/system/Format/JSONFormatter.php</b> on line <b>41</b><br />
{
    "title": "ErrorException",
    "type": "ErrorException",
    "code": 500,
    "message": "Uncaught CodeIgniter\\Format\\Exceptions\\FormatException: Failed to parse json string, error: \"Malformed UTF-8 characters, possibly incorrectly encoded\". in /home/mma/domains/***/ci4/vendor/codeigniter4/framework/system/Format/JSONFormatter.php:41\nStack trace:\n#0 /home/mma/domains/***/ci4/vendor/codeigniter4/framework/system/Format/JSONFormatter.php(41): CodeIgniter\\Format\\Exceptions\\FormatException::forInvalidJSON('Malformed UTF-8...')\n#1 /home/mma/domains/***/ci4/vendor/codeigniter4/framework/system/API/ResponseTrait.php(341): CodeIgniter\\Format\\JSONFormatter->format(Array)\n#2 /home/mma/domains/***/ci4/vendor/codeigniter4/framework/system/API/ResponseTrait.php(99): CodeIgniter\\Debug\\Exceptions->format(Array)\n#3 /home/mma/domains/***/ci4/vendor/codeigniter4/framework/system/Debug/Exceptions.php(115): CodeIgniter\\Debug\\Exceptions->respond(Array, 500)\n#4 [internal function]: CodeIgniter\\Debug\\Exceptions->exceptionHandler(Object(DomainException))\n#5",
    "file": "/home/mma/domains/***/ci4/vendor/codeigniter4/framework/system/Format/JSONFormatter.php",
    "line": 41,
    "trace": [
        {
            "function": "shutdownHandler",
            "class": "CodeIgniter\\Debug\\Exceptions",
            "type": "->",
            "args": []
        }
    ]
}

app/Filters/Auth.php:

<?php

namespace App\Filters;

use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

class Auth implements FilterInterface {

    public function before(RequestInterface $request, $arguments = null) {
        $key = getenv('JWT_SECRET');
        $header = $request->getServer('HTTP_AUTHORIZATION');
        $token = null;

        if (!empty($header)) {
            $token = explode(' ', $header)[1];
        }

        if (is_null($token) || empty($token)) {
            $response = [
                'status'    => 401,
                'error'     => true,
                'message'   => 'Token required.',
                'data'      => []
            ];
            echo json_encode($response);

            exit();
        }

        try {
            JWT::decode($token, new Key($key, 'HS256'));
        } catch (Exception $ex) {
            $response = [
                'status'    => 401,
                'error'     => true,
                'message'   => 'Access denied.',
                'data'      => []
            ];
            echo json_encode($response);

            exit();
        }
    }

    public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) {
        //
    }

}

How do I get response I created?


Solution

  • This is all about namespaces.

    When your file begins with a namespace declaration, every bare class name in the file is compiled as though that namespace was on the front of its name, unless one of two things applies:

    So, when the compiler sees this line:

    } catch (Exception $ex) {
    

    It is compiling it as though you wrote this:

    } catch (\App\Filters\Exception $ex) {
    

    But what you intended was the built-in class Exception, which is the base class for all user-land exceptions. As an FQCN, that would be written like this:

    } catch (\Exception $ex) {
    

    Or you could add a use statement for it, such as this:

    use Exception;
    

    Of course, if you wanted to handle this specific exception, you would instead write this:

    } catch (\CodeIgniter\Format\Exceptions\FormatException $ex) {
    

    Or more likely this:

    // near top of file
    use CodeIgniter\Format\Exceptions\FormatException;
    // ... many lines later ...
    } catch (FormatException $ex) {