Skip to content
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
Open

Any guide how to use on Laravel 5.5? #1316

johncloud200 opened this issue Sep 16, 2017 · 32 comments

Comments

@johncloud200
Copy link

HooOoo0ooW?

@andreolvr
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
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
Copy link

And how do i install this new version?

@donng
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
Copy link

Thanks, @donng. Already edited it.

@php2020
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
Copy link

donng commented Sep 20, 2017

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

@php2020
Copy link

php2020 commented Sep 21, 2017

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

@mbezhanov
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
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
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
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
Copy link

@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
Copy link

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

@mbezhanov
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
Copy link

@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
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
Copy link

@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
Copy link

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

@lomholdt
Copy link

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

@kamihouse
Copy link

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
Copy link

kamihouse commented Oct 3, 2017

Updated doc: https://github.com/tymondesigns/jwt-auth/blob/docs/docs/quick-start.md

@maximilianfixl
Copy link

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

@wapnen
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
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
Copy link

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

@billsion
Copy link

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
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
Copy link

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

@mbezhanov
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
Copy link

@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
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
Labels
None yet
Projects
None yet
Development

No branches or pull requests