Open johncloud200 opened 7 years ago
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.
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.
And how do i install this new version?
@andreolvr It really helps,but there is a little wrong.
I generate jwt secret using : php artisan jwt:secret
because command "jwt:generate" is not defined.
Thanks, @Donng. Already edited it.
"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"
@php2020 you should modify your App\User , it should implement JWTSubject ,just see the second answer.
@Donng Tymon \ JWTAuth \ Exceptions \ TokenInvalidException Token Signature could not be verified.
@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?
@mbezhanov
`<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request; use Validator; use JWTAuth;
class AuthController extends Controller { /**
@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);
}
}
/**
routes/api.php Route::post('gettoken', 'AuthController@authenticate');//I can get token! Route::post('getuser', 'AuthController@getUser');// I can't get user
@php2020 Have you set a "JWT_SECRET" in your .env file?
php artisan jwt:secret
e.g.
JWT_SECRET=uYa1uW32fUt7k7MLD9zVRq5EoyaTC3u
@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!
@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.
I installed the newest version (rc1), but the config/jwt.php file wasn't created, is it normal?
@andreolvr did you run:
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
?
This is what creates the config/jwt.php
file.
@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?
@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.
@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.
@lomholdt jwt.refresh
allows you to use an expired token, while jwt.renew
doesn't
@mbezhanov I have everything working now! Thanks a million! Very much appreciated.
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!
I updated composer with this requirement "tymon/jwt-auth": "^1.0.0-rc.1"
Works like a charme with laravel 5.5
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?
@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)
@maximilianfixl thanks man..it worked..thanks alot!
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
Do you have use JWTAuth;
and use Tymon\JWTAuth\Exceptions\JWTException;
?
How can I inject generated token to authenticated user and then response it ?
@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?
@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
hello! im getting this error
_"Symfony\Component\Debug\Exception\FatalThrowableError" file:"/var/www/html/sebi/adminint/vendor/tymon/jwt-auth/src/Providers/Auth/Illuminate.php" line:47 message:"Call to undefined method Illuminate\Auth\TokenGuard::once()"
any ideea?
HooOoo0ooW?