4

I have the following piece of code in Laravel BaseController. I want to protect all my api resources with an Authorization header with a token.

  public function __construct()
  {
    $this->beforeFilter('@getUserFromToken');
  }

  public function getUserFromToken($route, $request)
  {
    $accessToken = Request::header('Authorization');
    if(!empty($accessToken)){
      $this->currentUser = User::findByToken($accessToken);
    }else{
      return Request::header('Authorization'); //THE PROBLEM
      return Response::json(['error'=>'Not authorized. Access token needed in Header.Authorization'], 403);
    }
  }

Here is my .htaccess if that's relevant.

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews
    </IfModule>

    RewriteEngine On

    # Redirect Trailing Slashes...
    RewriteRule ^(.*)/$ /$1 [L,R=301]

    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
</IfModule>

So if I have the marked problem line, Apache will read everything perfectly. And I will get my responses back and not getting the 403. However, if I don't have that line, I will get 403 error with my custom error message. WHY? Obviously I am using the same code $this->currentUser = User::findByToken($accessToken);, why by leaving the marked line I'll be able to get the header? Is there a redirect happening behind the scene that sets the Authorization header somehow only the second time? Is there a setting that I missed for apache to pick up the header the first time?

UPDATE: I guess my question is: if I just return Response::json(['error'=>'Not authorized. Access token needed in Header.Authorization'], 403);, I will always get this error json. And my $accessToken will always be empty. Why?

MORE UPDATE: Looks like I shouldn't reuse Authorization Header? I tried:

$accessToken = Request::header('Custom-Token');
if(!empty($accessToken)){
  $this->currentUser = User::findByToken($accessToken);
}else{
  return Response::json(['error'=>'Not authorized. Access token needed in Header.Authorization'], 403);
}

And this time I'm able to get the real token. My question still stands then, why can I return the "magical" header and suddenly get it in Laravel?

This related question didn't answer it, but pointed me to the right direction: laravel 4: why is Request::header() not getting the specified header?

One more thing: the Authorization header does work without the magic return if I serve use php artisan serve, which uses php dev server.

Community
  • 1
  • 1
randomor
  • 5,329
  • 4
  • 46
  • 68

2 Answers2

16

It is a Laravel & Apache problem, this line in public/.htaccess fixed it for me:

RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

The fix is from https://github.com/dingo/api/issues/54

randomor
  • 5,329
  • 4
  • 46
  • 68
  • 1
    You are an angel. I banged my head for endless hours and could not figure out what went wrong. If it weren't for this answer I would go on using the token in the URL params which is not a clean approach if you ask me. I have raised a bounty and will award it to you as soon as Stack Overflow lets me. Thank you so much. :) – Rohan Jan 04 '15 at 18:20
  • 1
    @Rohan. Glad it also helped you. Don't worry about the bounty. Your comment is reward in itself. :) – randomor Jan 05 '15 at 00:09
0

You cannot have two returns in PHP:

return Request::header();
return Response::json();

So in your code, only the header will return, and your code will exit.

I think this will work

return Response::json(['error'=>'Not authorized. Access token needed in Header.Authorization'], 403)->header('Authorization');

If not - this definetely will:

$response = Response::json(['error'=>'Not authorized. Access token needed in Header.Authorization'], 403);
$response->header('Authorization');
return $response;
Laurence
  • 58,936
  • 21
  • 171
  • 212
  • I know. I'm only putting that code there while debugging, and somehow found a fix. I would like to do `return Response::json(['error'=>'Not authorized. Access token needed in Header.Authorization'], 403);` But my question is really why the `Authorization` value is empty when it came through. – randomor Jun 06 '14 at 16:18
  • I dont understand what you are asking - please expand on your question with more information. – Laurence Jun 06 '14 at 16:19
  • Not really. Why do you think $accessToken will be magically filled if you return a JSON error? – Laurence Jun 06 '14 at 16:23
  • I don't know why. That's the problem. :) I'm wondering if it's something with apache or my code. Anyway, if I do `return 'Your Header.Authorization is: '. $accessToken;`, it will always return `Your Header.Authorization is: `. If I do that "magic" return, I will get the results that I want. But I don't want the "magic" return all the time, only when I really truly don't have a Header.Authorization set. – randomor Jun 06 '14 at 16:26