Laravel:Error when Implementing JWT authentication - laravel

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);
}

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.');
}
}

Change Password using API Laravel

I was trying to do the change password using API Laravel. But it didn't work. I'm new to API Laravel.
Any suggestion to solve my problem?
public function __construct()
{
$this->middleware('auth');
}
public function store(ChangePasswordValidation $request)
{
if(Auth::check($data['current_password'], $user->password))
{
$user = User::find(Auth::user()->id)->update(["password"=> bcrypt($request->password)]);
$success['token'] = $user->createToken('newToken')->accessToken;
return response()->json(['success' => $success], 200);
}
else
{
return response()->json(['error'=>'Unauthorised'], 401);
}
}
the result shown in Postman is:
{
"message": "Unauthenticated."
}
You need to use guard as you are using API
so change
Auth::user()
To
Auth::user('api')
also
$this->middleware('auth');
To
$this->middleware('auth:api');
Edit this line
if(Auth::check($data['current_password'], $user->password))
Into
if(Auth::check($request['current_password'], $user->password))

Accessing Laravel Api using POSTMAN (404 not found)

I wrote an API for User Login using Laravel 5.8
When I tested the Login on Postman, it generated an error.
Status: 404 Not Found.
The File Path is Http->Controllers->UserController->Login
The project is laravelapi. I used POST in Postman and added this:
http://localhost/laravelapi/public/user/api/login
But when I run php artisan serve and used:
http://localhost:8000/api/login
Status was OK.
Controller
public function login(Request $request)
{
$credentials = $request->json()->all();
try {
if(! $token == JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'invalid_credentials'], 400);
}
} catch(JWTException $e) {
return response()->json(['error' => 'could_not_create_token'], 500);
}
return response()->json(compact('token'));
}
api.php
use Illuminate\Http\Request;
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
Route::post('login', 'UserController#login');
What do I do to make http://localhost/laravelapi/public/user/api/login work and have Status: OK
Thanks.
link must be localhost/laravelapi/public/api/login

How add new parameter to check in login Laravel

In LoginController I override the credentials method, like this:
protected function credentials(Request $request)
{
$credentials = $request->only($this->username(), 'password');
$credentials['status'] = User::STATUS_ACTIVE;
return $credentials;
}
And this work pretty fine. But when a try to add a parameter which is not a column of the Users table I don't know how to check there. Some like this:
protected function credentials(Request $request)
{
$credentials = $request->only($this->username(), 'password');
$credentials['status'] = User::STATUS_ACTIVE;
$credentials['customer-status'] = Customer::STATUS_ACTIVE;
return $credentials;
}
Where can I check if the value is correct? I tried to make an event listener to attempt login, but it doesn't work. My idea is to make an Eloquent query to return an account of customers activities. If more then one, customer-status for this user is true.
If anyone is interested in knowing how I solved it, the explanation is as follows:
Based on this code I found in github: https://gist.github.com/joseluisq/fb84779ea54eaebf54a9d8367117463e
In LoginController.php I override 2 methods(login and sendFailedLoginResponse):
public function login(Request $request)
{
$this->validateLogin($request);
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
$this->incrementLoginAttempts($request);
$user = User::where('email', $request->email)->first();
if (!$user) {
return $this->sendFailedLoginResponse($request);
}
$customers = Customer::join('users_customers', 'users_customers.customer_id', 'customers.id')
->where([
['users_customers.user_id', '=', $user->id],
['customers.status', '=', Customer::STATUS_ACTIVE]
])
->count();
if ($customers === 0) {
return $this->sendFailedLoginResponse($request, 'auth.inactive');
}
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
}
return $this->sendFailedLoginResponse($request);
}
protected function sendFailedLoginResponse(Request $request, $trans = 'auth.failed')
{
$errors = ['email' => trans($trans)];
if ($request->expectsJson()) {
return response()->json($errors, 422);
}
return redirect()
->back()
->withErrors($errors);
}
Remember yourself to define message on auth.php and set uses needed.
Ps.: I don't use $credentials['customer-status'] = Customer::STATUS_ACTIVE;,
as I thought I would.

JWT Authentication user_not_found Tymon

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);
}

Resources