New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Any guide how to use on Laravel 5.5? #1316

Open
johncloud200 opened this Issue Sep 16, 2017 · 32 comments

Comments

Projects
None yet
@johncloud200
Copy link

johncloud200 commented Sep 16, 2017

HooOoo0ooW?

@andreolvr

This comment has been minimized.

Copy link

andreolvr commented Sep 17, 2017

I got it working by doing this:

Add "tymon/jwt-auth": "dev-develop" to your require in composer.json then run composer update

Add the service provider to the providers array in your app.php config:
Tymon\JWTAuth\Providers\LaravelServiceProvider::class

Next, also in the app.php config file,add the JWTAuth facade and JWTFactory facade:

'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class

Run:
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
and then, run:
php artisan jwt:secret

Your user model should look like this:

<?php

namespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Tymon\JWTAuth\Contracts\JWTSubject;

class User extends Authenticatable implements JWTSubject
{
    /**
     * Get the identifier that will be stored in the subject claim of the JWT.
     *
     * @return mixed
     */
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    /**
     * Return a key value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims()
    {
        return [];
    }
}

Authentication controller:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Validator;
use JWTAuth;

class AuthController extends Controller
{
    /**
     * Authenticate an user.
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function authenticate(Request $request)
    {
        $credentials = $request->only('email', 'password');

        $validator = Validator::make($credentials, [
            'email' => 'required|email',
            'password' => 'required'
        ]);

        if ($validator->fails()) {
            return response()
                ->json([
                    'code' => 1,
                    'message' => 'Validation failed.',
                    'errors' => $validator->errors()
                ], 422);
        }

        $token = JWTAuth::attempt($credentials);

        if ($token) {
            return response()->json(['token' => $token]);
        } else {
            return response()->json(['code' => 2, 'message' => 'Invalid credentials.'], 401);
        }
    }

    /**
     * Get the user by token.
     *
     * @param  Request  $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getUser(Request $request)
    {
        JWTAuth::setToken($request->input('token'));
        $user = JWTAuth::toUser();
        return response()->json($user);
    }
}

That's it.

@ghost

This comment has been minimized.

Copy link

ghost commented Sep 18, 2017

Note that on the newest version (rc1) you shouldn't need to add the ServiceProvider to the app.php file anymore since it's compatible with Laravel 5.5's automatic discovery feature.

@andreolvr

This comment has been minimized.

Copy link

andreolvr commented Sep 18, 2017

And how do i install this new version?

@Donng

This comment has been minimized.

Copy link

Donng commented Sep 19, 2017

@andreolvr It really helps,but there is a little wrong.

  • JWTAuth facade is "Tymon" not "'y" ,
  • I generate jwt secret using : php artisan jwt:secret

because command "jwt:generate" is not defined.

@andreolvr

This comment has been minimized.

Copy link

andreolvr commented Sep 19, 2017

Thanks, @Donng. Already edited it.

@php2020

This comment has been minimized.

Copy link

php2020 commented Sep 20, 2017

"Type error: Argument 1 passed to Tymon\JWTAuth\JWT::fromUser() must be an instance of Tymon\JWTAuth\Contracts\JWTSubject, instance of App\User given, called in C:\xampp\htdocs\laravel55\vendor\tymon\jwt-auth\src\JWTAuth.php on line 54"

@Donng

This comment has been minimized.

Copy link

Donng commented Sep 20, 2017

@php2020 you should modify your App\User , it should implement JWTSubject ,just see the second answer.

@php2020

This comment has been minimized.

Copy link

php2020 commented Sep 21, 2017

@Donng
Tymon \ JWTAuth \ Exceptions \ TokenInvalidException
Token Signature could not be verified.

@mbezhanov

This comment has been minimized.

Copy link

mbezhanov commented Sep 21, 2017

@php2020 When does that exception get thrown exactly? When a HTTP Request hits your middleware, or when you manually try to validate a token? Can you share some sample code please?

@php2020

This comment has been minimized.

Copy link

php2020 commented Sep 21, 2017

@mbezhanov

`<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Validator;
use JWTAuth;

class AuthController extends Controller
{
/**
* Authenticate an user.
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function authenticate(Request $request)
{
$credentials = $request->only('email', 'password');

    $validator = Validator::make($credentials, [
        'email' => 'required|email',
        'password' => 'required'
    ]);

    if ($validator->fails()) {
        return response()
            ->json([
                'code' => 1,
                'message' => 'Validation failed.',
                'errors' => $validator->errors()
            ], 422);
    }

    $token = JWTAuth::attempt($credentials);

    if ($token) {
        return response()->json(['token' => $token]);
    } else {
        return response()->json(['code' => 2, 'message' => 'Invalid credentials.'], 401);
    }
}

/**
 * Get the user by token.
 *
 * @param  Request  $request
 * @return \Illuminate\Http\JsonResponse
 */
public function getUser(Request $request)
{
    JWTAuth::setToken($request->input('token'));
    $user = JWTAuth::toUser();
    return response()->json($user);
}

}`

routes/api.php
Route::post('gettoken', 'AuthController@authenticate');//I can get token!
Route::post('getuser', 'AuthController@getUser');// I can't get user

@mbezhanov

This comment has been minimized.

Copy link

mbezhanov commented Sep 21, 2017

@php2020 Have you set a "JWT_SECRET" in your .env file?

php artisan jwt:secret

e.g.

JWT_SECRET=uYa1uW32fUt7k7MLD9zVRq5EoyaTC3u

@php2020

This comment has been minimized.

Copy link

php2020 commented Sep 21, 2017

@mbezhanov
`$ php artisan jwt:secret

This will invalidate all existing tokens. Are you sure you want to override the secret key? (yes/no) [no]:

yes

jwt-auth secret [Pq5nm2BLxo1sClPJhH65X3pTWfyXzh41] set successfully.`

My fault, before .env was not covered, I can get user! thank you!

@mbezhanov

This comment has been minimized.

Copy link

mbezhanov commented Sep 21, 2017

@php2020 I personally use the built-in jwt.auth middleware in my API controllers like this:

class FooController extends Controller
{
    public function __construct()
    {
        $this->middleware('jwt.auth');
    }
}

With this middleware, if a JWT token is invalid or expired, a HTTP 401 status code will be returned. My JS clients (API clients) then react to the 401 responses, by attempting to obtain a new token, and redirecting to a login page upon failure, where the user is supposed to re-type her username and password, in order to obtain a new token.

Not sure this is the best way out there, but that's what I've been doing so far with good success.

@andreolvr

This comment has been minimized.

Copy link

andreolvr commented Sep 22, 2017

I installed the newest version (rc1), but the config/jwt.php file wasn't created, is it normal?

@mbezhanov

This comment has been minimized.

Copy link

mbezhanov commented Sep 22, 2017

@andreolvr did you run:

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"?

This is what creates the config/jwt.php file.

@lomholdt

This comment has been minimized.

Copy link

lomholdt commented Sep 23, 2017

@mbezhanov How exactly do you refresh a token? I followed @andreolvr example above, but now I have an expired token that can't be refreshed. I'm wondering how you do that?

@mbezhanov

This comment has been minimized.

Copy link

mbezhanov commented Sep 24, 2017

@lomholdt Generally speaking, I use the jwt.renew middleware bundled with the library, but this won't work with expired tokens (for a solution with expired tokens, see the bottom part of my post)

// in the routes file:
Route::post('auth/renew', 'AuthController@renew');

// in the Controller:
class AuthController extends Controller
{
    public function __construct()
    {
        $this->middleware('jwt.renew')->only('renew');
    }

    public function renew()
    {
        return;
    }
}

What this does is that whenever you issue a request to /auth/renew with a valid JWT token, you will get a new token back. The new token is sent in the "Authorization" header of the HTTP Response. Note that the previous token will get blacklisted. This means you can't use a JWT token for requesting a new token more than once, which is really good, because it makes your system more secure.

On the JS side, there are many possible solutions, and I haven't heard of a particular one to be considered a standard (please feel free to correct me here if you know of a standardized one) The most secure one, I guess, would be to renew your token on every HTTP request to the API - I've read that certain APIs do this. However, I feel that this may be a bit too much, so I prefer to use a simpler solution, where I have my JS client keep track of the expiration time of the current token (stored in the "exp" claim) and have it renew the token before it expires.

How this works in practice: let's say the API issues a token having an expiration time of 20 minutes. If the client detects that there are less than 10 minutes left before the token expires, it will go ahead and make a new request to "/auth/renew", in order to obtain a new token.

That way the JS client will never log you out, as long as there is a reasonable amount of activity, and if there's not - the token will expire, so the user will have to reauthenticate using username and password, in order to obtain a token.


Alertnatively, you can refresh an expired token, by using the jwt.refresh middleware, like this:

// in the routes file:
Route::post('auth/refresh', 'AuthController@refresh');

// in Controller
class AuthController extends Controller
{
    public function __construct()
    {
        $this->middleware('jwt.refresh')->only('refresh');
    }

    public function refresh()
    {
        return;
    }
}

With this middleware, you can have your JS Client intercept 401 errors, and attempt to refresh the token by calling the /auth/refresh route.

@lomholdt

This comment has been minimized.

Copy link

lomholdt commented Sep 25, 2017

@mbezhanov Thanks a million! This was really helpfull! I got the refresh working! Do you know if it's possible to refresh an expired token with the refresh middleware? Or will it only refresh a valid token.

@mbezhanov

This comment has been minimized.

Copy link

mbezhanov commented Sep 25, 2017

@lomholdt jwt.refresh allows you to use an expired token, while jwt.renew doesn't

@lomholdt

This comment has been minimized.

Copy link

lomholdt commented Sep 25, 2017

@mbezhanov I have everything working now! Thanks a million! Very much appreciated.

@kamihouse

This comment has been minimized.

Copy link

kamihouse commented Oct 2, 2017

Hi guys.
Do you know of any way to override the user model?

I'm trying to use multi-authentication, so in my controller on constructor, based on the routes, I add the code Config::set('auth.providers.users.model', Models/Usuario::class) so I can call the JWTAuthmethod::attempt($credentials); fine.

Is there any better way to do this?
Thanks!

@kamihouse

This comment has been minimized.

@maximilianfixl

This comment has been minimized.

Copy link

maximilianfixl commented Oct 11, 2017

I updated composer with this requirement "tymon/jwt-auth": "^1.0.0-rc.1"
Works like a charme with laravel 5.5

@wapnen

This comment has been minimized.

Copy link

wapnen commented Oct 12, 2017

hi guys, i tried to make the token last forever by changing the ttl to null and removing the 'exp' from required claims but when i try to authenticate (create a token via a login request) i always get a 'token has expired' exception.
anyone know a way out?

@mbezhanov

This comment has been minimized.

Copy link

mbezhanov commented Oct 12, 2017

@wapnen In .env, set JWT_TTL=null, and also in config/jwt.php remove exp from required_claims, so that it's defined like this:

'required_claims' => [
    'iss',
    'iat',
    'nbf',
    'sub',
    'jti',
],

Finally do:

php artisan config:clear

...and it should work (tested and working on the 1.0.0-rc1 version)

@achchu93

This comment has been minimized.

Copy link

achchu93 commented Oct 26, 2017

@maximilianfixl thanks man..it worked..thanks alot!

@billsion

This comment has been minimized.

Copy link

billsion commented Nov 10, 2017

When I call:

JWTAuth::attempt($credentials)

I've got the fowling error:
Class 'Tymon\JWTAuth\Providers\JWT\NamshiAdapter' not found

why is that?

thanks in advance

@maximilianfixl

This comment has been minimized.

Copy link

maximilianfixl commented Nov 10, 2017

Do you have use JWTAuth; and use Tymon\JWTAuth\Exceptions\JWTException;?

thuytiensp added a commit to thuytiensp/laravel_restapi_demo that referenced this issue Nov 11, 2017

tienttt pushed a commit to thuytiensp/laravel_restapi that referenced this issue Nov 14, 2017

@ahmadbadpey

This comment has been minimized.

Copy link

ahmadbadpey commented Nov 15, 2017

How can I inject generated token to authenticated user and then response it ?

@mbezhanov

This comment has been minimized.

Copy link

mbezhanov commented Nov 15, 2017

@billsion assuming you are using version 1.0.0-rc1, along with the things @maximilianfixl mentioned, maybe try refreshing your autoload classmap via composer dumpautoload (if you haven't done so already)

However, it looks to me that you may be having an issue with an older version, as Tymon\JWTAuth\Providers\JWT\NamshiAdapter was present until version 0.5.12 and removed since 1.0.0-alpha1. In 1.0.0 the provider is called Tymon\JWTAuth\Providers\JWT\Namshi

@ahmadbadpey can you clarify your question please?

@jass-trix

This comment has been minimized.

Copy link

jass-trix commented Dec 14, 2017

@mbezhanov so the workflow to do the refresh is when it is caught as unauthorized (401) by the interceptor then we're just gonna do a refresh with the token? then re-set the default authorization header for the next request

@cebik16

This comment has been minimized.

Copy link

cebik16 commented Jul 11, 2018

hello! im getting this error

"Symfony\Component\Debug\Exception\FatalThrowableError"
file:"/var/www/html/sebi/admin_int/vendor/tymon/jwt-auth/src/Providers/Auth/Illuminate.php"
line:47
message:"Call to undefined method Illuminate\Auth\TokenGuard::once()"

any ideea?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment