2

I've gone around the multiple posts around the same issue and it can't seem to cover my case.

My idea:

I'm using JWT to authenticate users and my idea is to determine that whenever a token is nearly expiration date, I want to return a new token within the headers (Header Authorization).

I've got this middleware made, just to test some things out

public function handle($request, Closure $next)
    {
        try {
            $user = JWTAuth::parseToken()->authenticate();
            $claims = JWTAuth::getPayload(JWTAuth::getToken())->toArray();

            if ($claims['exp'] - (strtotime(date("Y-m-d H:i:s"))) <= 900) {
                $token = JWTAuth::refresh(JWTAuth::getToken());
                header('Authorization: Bearer ' . $token);
            }
        } catch (Exception $e) {
            if ($e instanceof \Tymon\JWTAuth\Exceptions\TokenInvalidException) {
                return $this->response([], 'Authorization Token is Invalid', 401);
            } elseif ($e instanceof \Tymon\JWTAuth\Exceptions\TokenExpiredException) {
                try {
                    $token = JWTAuth::refresh(JWTAuth::getToken());
                    header('Authorization: Bearer ' . $token);
                    return $this->response([], 'Authorization Token is Expired', 401);
                } catch (\Tymon\JWTAuth\Exceptions\JWTException $e) {
                    return $this->response([], 'Authorization Token is Invalid', 401);
                }
            } else {
                return $this->response([], 'Authorization Token not found', 401);
            }
        }
        return $next($request);
    }

So far so good, testing with POSTMAN I get my desirable outcome. However, I went along to write down an acceptance test in order to test that indeed, this is correct.

public function testUserReceivesNewTokenInHeaderWhenExpiresAtIsWithin15Minutes()
    {
        //Arrange
        $token = JWTAuth::claims(['exp' => strtotime("+1 minutes", strtotime(date('Y-m-d H:i:s')))])->fromUser($this->user);
        $this->headers['HTTP_Authorization'] = "Bearer $token";
        //Act
        $response = $this->get('/api/justAnotherURL', $this->headers);
        //Assert
        $response->assertStatus(200);
        $this->assertTrue($response->headers->has('Authorization'));
    }

I set the exp date to be within the next minute (so it enters the validation above), it does enter as expected, but when it reaches Header(Authorization: Bearer $token), it throws an Exception:

Cannot modify header information - headers already sent by (output started at /var/www/project/vendor/phpunit/phpunit/src/Util/Printer.php:109)

As far as my research goes (and attempts), it's something about outputting the request on the console, but I've been unsuccessful so far.

Related post: How to fix "Headers already sent" error in PHP

Small notes:

this->response is my own custom response to the request, you can ignore that

Tried @runInSeparateProcess from another post and error dissapears, but the header isn't set (default header is returned)

Edit: I've tried placing the header at the top of the file, before the try catch and it remains the same (I was wondering if jwt would make some output without me knowing) and this is the only middleware being used atm

abr
  • 2,071
  • 22
  • 38
  • 1
    I suspect that your direct calls to `header()` should not be written that way. I don't use Laravel, but [you can attach headers to your response](https://laravel.com/docs/5.7/responses#attaching-headers-to-responses) before returning it - I'd suggest giving that a go – scrowler Feb 10 '19 at 12:56
  • I'll take a look whenever I got the time, thank you for the input @RobbieAverill – abr Feb 11 '19 at 10:34

0 Answers0