JWT Authentication user_not_found Tymon - laravel

I have set up Tymon Package for JWT Authentication. In case of new user sign up or login I get the token successfully. But when I pass the token to the Laravel JWT I get an error as user not found.
controller code
public function authenticate()
{
$credentials = request()->only('user_name','password');
try{
$token = JWTAuth::attempt($credentials);
if(!$token){
return response()->json(['error'=>'invalid_credentials'],401);
}
}
catch(JWTException $e){
return response()->json(['error'=>'something went wrong'],500);
}
return response()->json(['token'=>$token],200);
}
public function register()
{
$user_name = request()->user_name;
$c_name = request()->company_name;
$accessibility_level = request()->accessability_level;
$password = request()->password;
$contact_number = request()->contact_number;
$address = request()->address;
$user = User::create([
'user_name'=>$user_name,
'c_name'=>$c_name,
'accessibility_level'=>$accessibility_level,
'password'=>bcrypt($password),
'contact_number'=>$contact_number,
'address'=>$address
]);
$token = JWTAuth::fromUser($user);
return response()->json(['token'=>$token],200);
}
no problem with the above code works fine.
But when I try to access some data with JWT validation I get an error as USER_NOT_FOUND. I have passed the Token which I have got as an header through Postman.
Route Code
Route::get('/some_route','some_controller#index')->middleware('jwt.auth');
And the jwt.php is also set with the correct identifier which I have used in the model(Primary key)
'identifier' => 'user_name',

The JWT identifier doesn't work by simply modifying the config because it's hardcoded as id in the code for some reason
You can of course use the setIdentifier method before calling any other JWTAuth methods to set the identifier.
Here's how:
public function authenticate()
{
$credentials = request()->only('user_name','password');
try{
$token = JWTAuth::setIdentifier('user_name')->attempt($credentials);
if(!$token){
return response()->json(['error'=>'invalid_credentials'],401);
}
}
catch(JWTException $e){
return response()->json(['error'=>'something went wrong'],500);
}
return response()->json(['token'=>$token],200);
}
Then create a custom middleware for jwt authentication:
public function handle($request, \Closure $next)
{
if (! $token = $this->auth->setIdentifier('user_name')->setRequest($request)->getToken()) {
return $this->respond('tymon.jwt.absent', 'token_not_provided', 400);
}
try {
$user = $this->auth->authenticate($token);
} catch (TokenExpiredException $e) {
return $this->respond('tymon.jwt.expired', 'token_expired', $e->getStatusCode(), [$e]);
} catch (JWTException $e) {
return $this->respond('tymon.jwt.invalid', 'token_invalid', $e->getStatusCode(), [$e]);
}
if (! $user) {
return $this->respond('tymon.jwt.user_not_found', 'user_not_found', 404);
}
$this->events->fire('tymon.jwt.valid', $user);
return $next($request);
}

Related

Laravel - LogicException: App\Models\User::token must return a relationship instance, but "null" was returned

In Laravel-8, I am creating an end point for ForgotPassword and to also send notification to the user email:
public function forgotPassword(ResetPasswordRequest $request)
{
try {
$user = User::where('email', $request->email)->first();
if (!$user){
return $this->error('We can\'t find a user with that e-mail address.', 400);
}
$email = $request->email;
$token = Str::random(10);
$passwordReset = PasswordReset::updateOrCreate(
['email' => $user->email],
[
'email' => $email,
'token' => $token,
'created_at' => now()->addHours(10),
]
);
// Send Email Based on condition
if ($user && $passwordReset){
$user->notify(
new PasswordResetRequest($token)
);
}
return $this->success('We have e-mailed your password reset link!', [
'user' => $user,
]);
} catch(\Exception $e) {
Log::error($e);
return $this->error($e->getMessage(), $e->getCode());
}
}
As I submit, I got this error:
local.ERROR: LogicException: App\Models\User::token must return a relationship instance, but "null" was returned
When I removed:
if ($user && $passwordReset){
$user->notify(
new PasswordResetRequest($token)
);
}
Notification:
class PasswordResetRequest extends Notification
{
use Queueable;
protected $token;
public function __construct($token)
{
$this->token = $token;
}
public function via($notifiable)
{
return ['mail'];
}
public function toMail($notifiable)
{
$url = url('http://localhost:4200/reset-password-submit?token='.$this->token);
return (new MailMessage)
->line('You are receiving this email because we received a password reset request for your account.')
->action('Reset Password', url($url))
->line('If you did not request a password reset, no further action is required.');
}
}
No error, and it was also inserted into the password_resets table. but I need to send notification.
User and PasswordReset models are not even related.
How do I get this resolved?
Thanks
It seems like when using $this->token in the Notification, you're not getting the PasswordResetRequest $token attribute: you're getting the User Passport Token
Try changing the token variable name to something else.
class PasswordResetRequest extends Notification
{
use Queueable;
protected $url_token;
public function __construct($url_token)
{
$this->url_token = $url_token;
}
public function via($notifiable)
{
return ['mail'];
}
public function toMail($notifiable)
{
$url = url('http://localhost:4200/reset-password-submit?token='.$this->url_token);
return (new MailMessage)
->line('You are receiving this email because we received a password reset request for your account.')
->action('Reset Password', url($url))
->line('If you did not request a password reset, no further action is required.');
}
}

Laravel:Error when Implementing JWT authentication

I am experiencing an error when trying to post the API through Postman to authenticate users in the site.
login function:
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
if ($token = $this->guard()->attempt($credentials)) {
return $this->respondWithToken($token);
}
return response()->json(['error' => 'Unauthorized'], 401);
}
the guard function
public function guard()
{
return Auth::guard();
}
The error shown on postman
"message": "Call to undefined method Tymon\\JWTAuth\\Contracts\\Providers\\Auth::guard()",
"exception": "Symfony\\Component\\Debug\\Exception\\FatalThrowableError",
How to solve this?
You can use \JWTAuth::attempt function in order to get token if the user inserts valid email and password like:
....
use Tymon\JWTAuth\Exceptions\JWTException;
....
try {
$token = \JWTAuth::attempt($request->only('email', 'password'));
return $this->respondWithToken($token);
} catch (JWTException $exception) {
return response()->json([
'status' => false,
'data' => null,
'message' => 'Could not create token'
]);
}
EDIT 1
The above answer you submitted is correct.
try replacing Auth::guard() to Auth::guard('api')
public function guard()
{
return Auth::guard('api');
}
For more information there is a similar issue in GitHub for reference
Use a construct method like
public function __construct(){
auth()->setDefaultDriver('api');
}
and your login function like
public function login(){
$credentials = request(['email', 'password']);
if(!$token = auth()->attempt($credentials)){
return response()->json(['error' => 'Incorrect email/password'], 401);
}
return $this->respondWithToken($token);
}
And comment out your guard function
I have faced this problem continuously. But the solution was when I used bcrypt() on the password.
bcrypt($password);
Use dependency injection and inject the Auth interface into your class. Code example below.
From the Tymon package import the Auth interface.
use Tymon\JWTAuth\Contracts\Providers\Auth;
In your constructor
public function __construct(Auth $auth)
{
$this->_authentication = $auth;
}
Then use the "byCredentials" method
if (! $token = $this->_authentication->byCredentials($credentials))
{
return response()->json(['message' => 'Unauthorized'], 401);
}

How to verifiy JWT on a single route in Laravel

I have a single route in Laravel on which I need to verify the JWT on header if it is authorized and not expired. How can I do that?
In Javascript its really easy, but don`t know how in Laravel.
Here's the code:
public function update(Request $request){
$header = $request->header('Authorization');
$token = $request->bearerToken();
$secret = env('EXAMPLE_SECRETE');
$verified = here i want to verify the jtw /$token
if (!verified)
return 'something here'
else
>>code here after verified
}
First of install below package
composer require firebase/php-jwt
And then you can create a middleware in order to verify Token or expired, below is a complete code of middlware
namespace App\Http\Middleware;
use Closure;
use Exception;
use App\User;
use Firebase\JWT\JWT;
use Firebase\JWT\ExpiredException;
class JwtTokenMiddleware
{
public function handle($request, Closure $next, $guard = null)
{
$token = $request->bearerToken();
if (!$token) {
// Unauthorized response if token not there\
}
try {
$credentials = JWT::decode($token, env('JWT_SECRET'), ['HS256']);
//You can get credentials that you have set up while generating token
$user = User::findOrFail($credentials->sub)->setAuthUser();
$request->auth = $user;
} catch (ExpiredException $e) {
// Token expired response
} catch (Exception $e) {
// Handle unknow error while decoding token
return response()->json([
}
return $next($request);
}
}

Switching user in laravel 5.4

I am switching users in laravel and I succeeded in that as well but the thing is when I redirect the user to the dashboard after successful login it redirects to login form instead I don't know what am I doing wrong. Here is the code I am using.
public function user_reauthenticate(Request $request) {
$input = Input::all();
$data = User::where('email', $input['email'])->first();
if ($data) {
if (Hash::check($input['password'], $data->password)) {
Session::put('email', $input['email']);
$newuser = Student::find($input['new_user']);
session(['orig_user' => $data->id]);
Auth::login($newuser);
return Redirect::back();
} else {
$response = 'Wrong Credentials';
}
} else {
$response = 'User does not exist';
}
}
Can anyone help me find out the issue?
Edited
You can log in with
Auth::loginUsingId(1);
New edited
// If you have the guard student and multiple auth
$auth = auth()->guard('student');
$objAuth = $auth->loginUsingId($input['new_user']);
//Single Auth
$objAuth = Auth::loginUsingId($input['new_user']);
Add this to your top of the file:- use Illuminate\Foundation\Auth\AuthenticatesUsers;
Afterwards add a if function like below in your already completed code:-
public function user_reauthenticate(Request $request)
{
use AuthenticatesUsers;
$input = Input::all();
$data = User::where('email', $input['email'])->first();
if ($data) {
if (Hash::check($input['password'], $data->password))
{
Session::put('email', $input['email']);
$newuser = Student::find($input['new_user']);
session(['orig_user' => $data->id]);
Auth::login($newuser);
if ($this->attemptLogin($request))
{
return $this->sendLoginResponse($request);
}
}
else
{
$response = 'Wrong Credentials';
}
}
else
{
$response = 'User does not exist';
}
}
After this method override this method as follows:-
protected function authenticated(Request $request, $user)
{
return redirect()->route('dashboard');
}
Check whether your dashboard route is named dashboard or if not name it.

tymon/jwt-auth for laravel 5.4 refresh token

I recently using laravel 5.4 and I want to use tymon/jwt-auth package to secure my APIs by sending the access token but my issues happened when token expired I can't refresh it before expired and I expected the token will be refreshed automatically
public function handle($request, Closure $next)
{
try{
$user = JWTAuth::parseToken()->authenticate();
}catch (JWTException $e) {
if($e instanceof \Tymon\JWTAuth\Exceptions\TokenExpiredException) {
return response()->json(['token_expired'], $e->getStatusCode());
}else if ($e instanceof \Tymon\JWTAuth\Exceptions\TokenInvalidException) {
return response()->json(['token_invalid'], $e->getStatusCode());
}else{
return response()->json(['error'=>'Token is required']);
}
}
return $next($request);
}
You only need this snippet to do authentication:
$credentials = request(['email', 'password']);
if (!$token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
Make sure you include jwt.auth & jwt.refresh on middleware at route as follow:
Route::Group(['middleware' => [
'jwt.auth',
'jwt.refresh',
]], function() {
//list your route here
....
....
....
jwt.refresh do refresh your token each time you access the route. And also added this in your .env
JWT_BLACKLIST_GRACE_PERIOD=60
you can adjust the number from 60 seconds to any other values. This setting will set how long the token will valid before refreshed again.

Resources