tymondesigns / jwt-auth

🔐 JSON Web Token Authentication for Laravel & Lumen
https://jwt-auth.com
MIT License
11.28k stars 1.55k forks source link

Getting exception while parseToken() in Laravel 4.2 (token passed by POST) #109

Closed uberzhilkin closed 9 years ago

uberzhilkin commented 9 years ago

Hello, this is my first issue at GitHub, sorry for any mistakes. Didn't find the exact problem in open/closed issues so decided to start a new one.

My setup is Laravel 4.2 and JWTAuth 0.4.3. I'm building an API for a mobile app and I've decided to use tokens for authenification. The scenario is simple: first, the app provides user email/password pair (and the app key) to get the token. Next, the app addresses the user_info URL providing the token (and app_key again) to retrieve some user-related information.

The whole thing works abosultely fine through the GET-methods. I've created a test user with email "test@test.test" and password "testtesttest". The test app-key is "secret" and I manage to get the token by calling:

_http://anylanguage.ru:1488/api/user_auth?email=test@test.test&password=testtesttest&app_key=secret_

{"code":200,"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJzdWIiOiIxNiIsImlzcyI6Imh0dHA6XC9cL2FueWxhbmd1YWdlLnJ1OjE0ODhcL2FwaVwvdXNlcl9hdXRoIiwiaWF0IjoiMTQzMDgyMjQ4NSIsImV4cCI6IjE0MzA4MjYwODUiLCJuYmYiOiIxNDMwODIyNDg1IiwianRpIjoiMDNmOWY5YjQ5NjBkOTlkN2IzZGE1YWNjYzIzNDRhM2UifQ.OTk3MjFlYWQ5YzFlYmUxYjU1MjIyMWQ2ZDVhOTZlNzZkZDU1YmM4ODg5NWQ2MWUyOTgwNGE1N2ZjY2U4OWRkMw"}

Next, I provide the token to user_info URL: _http://anylanguage.ru:1488/api/user_info?app_key=secret&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJzdWIiOiIxNiIsImlzcyI6Imh0dHA6XC9cL2FueWxhbmd1YWdlLnJ1OjE0ODhcL2FwaVwvdXNlcl9hdXRoIiwiaWF0IjoiMTQzMDgyMjQ4NSIsImV4cCI6IjE0MzA4MjYwODUiLCJuYmYiOiIxNDMwODIyNDg1IiwianRpIjoiMDNmOWY5YjQ5NjBkOTlkN2IzZGE1YWNjYzIzNDRhM2UifQ.OTk3MjFlYWQ5YzFlYmUxYjU1MjIyMWQ2ZDVhOTZlNzZkZDU1YmM4ODg5NWQ2MWUyOTgwNGE1N2ZjY2U4OWRkMw_

{"code":200,"user":{"id":"16","role_id":"2","photo_id":"183","email":"test@test.test","username":"testtesttest","confirmed":"1","confirm_code":"$2y$10$58BU9LMNCs9ttal9fpQKEud3iuOCqmsEDr0N1dAFSxGETRzI3.2Ci","remind_code":null,"service":null,"remote_id":null,"first_name":"Test","last_name":"Tester","country_id":"1","city_id":"35","birthdate":"1990-06-07","phone":null,"gender":"1","sms_code":null,"sms_verify_sent_at":null,"sms_verified":null,"sms_verify_tries":null,"ya_money":null,"prefer":"0","translator_status":null,"last_visit":null,"banned":"0","rating_total":null,"rating_count":null,"rating_internal":null,"rating_system":null,"notify_type":"2","social_vk":null,"social_facebook":null,"social_linkedin":null,"website":null,"translate_verbal":"0","translate_written":"0","headline":null,"finance_institution_type":null,"correct":"1","admin":"0","deleted_at":null,"created_at":"2015-05-02 09:07:41","updated_at":"2015-05-02 12:46:01"}}

I get stuck with the POST-method, though. I use the hurl.it to get the token and it is generated just fine: image image

Yet when I try to pass the token to user_info URL I get the "token absent" error: image image

When I try to pass the token through header parameters it throws a different "token invalid" exception.

I catch all JWT-exceptions globally at global.php:

App::error(function(Tymon\JWTAuth\Exceptions\JWTException $e, $code)
{
    if ($e instanceof Tymon\JWTAuth\Exceptions\TokenExpiredException) {
        return Response::json([ 'code' => $e->getStatusCode(), 'msg' => 'token_expired' ]);
    } else if ($e instanceof Tymon\JWTAuth\Exceptions\TokenInvalidException) {
        return Response::json([ 'code' => $e->getStatusCode(), 'msg' => 'token_invalid' ]);
    }
    if( $e instanceof Tymon\JWTAuth\Exceptions\JWTException ){
        return Response::json([ 'code' => $e->getStatusCode(), 'msg' => 'token_absent' ]);
    }
});

All the requests to user_info URL are filtered for valid token presence like this: routes.php

Route::group( [ 'prefix' => '/api' ], function(){
    Route::group( [ 'before' => 'appKeyCheck' ], function(){
        Route::any( '/user_auth', [ 'as'=>'api.user_auth',
                                         'uses'=>'ApiController@userAuth' ] );

        Route::group(['before'=>'apiTokenCheck'], function(){
            Route::any( '/user_info', [ 'as'=>'api.user_info',
                                             'uses'=>'ApiController@userInfo' ] );
            Route::any( '/check_auth', [ 'as'=>'api.check_auth',
                                             'uses'=>'ApiController@checkAuth' ] );
        });
    });
});

filters.php

Route::filter('apiTokenCheck', function()
{   
    JWTAuth::setToken( Input::get( 'token' ) );
    //dd( JWTAuth::getToken() );

    if ( ! JWTAuth::parseToken()->authenticate() ) {
        return Response::json( [    'code' => ApiController::USER_NOT_FOUND,    
                                    'msg' => 'user_not_found' ] );
    }
});

You may notice the strange line "JWTAuth::setToken( Input::get( 'token' ) );" and the commented "dd( JWTAuth::getToken() );" one. These were to assure the token stored in JWTAuth is the one I pass through the POST-method. The dd() call prints exactly the same token I pass through POST-method (wherther I call setToken() before or not) so I have now I'm really stuck here wihtout an idea where to move forward. Would be grateful for the answer if it is my error or the package's one.

Thank you!

tymondesigns commented 9 years ago

Are you using apache?

tymondesigns commented 9 years ago

If you are then #81 and this SO post should help

uberzhilkin commented 9 years ago

No, I'm using nginx with a common Laravel configuration

        location / {
                try_files $uri $uri/ /index.php?$query_string;
        }

        location ~ \.php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass unix:/var/run/php5-fpm.sock;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
            fastcgi_read_timeout 300;
        }

Still will read the post you mentioned - maybe it will help

tymondesigns commented 9 years ago

oh ok.. next thing to try is the workaround described here #72

tymondesigns commented 9 years ago

This will be part of the next release btw

uberzhilkin commented 9 years ago

@tymondesigns, this worked for me:

filters.php

App::before(function ($request) {
        if(isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])){
            $request->headers->set('AUTHORIZATION',$_SERVER['REDIRECT_HTTP_AUTHORIZATION']);
        }
});

Now I'm able to pass the token from my mobile app. Thanks a lot!