Laravel: Target [Lcobucci\JWT\Parser] is not instantiable - php

Hey I am having an issue on my prod website trying to log in with Laravel passport. It says my Lcobucci JWT Parser is not instantiable. It works for me locally but not on my remote.
How can I resolve this?
Error:
exception: "Illuminate\Contracts\Container\BindingResolutionException"
file: "/var/www/html/vendor/laravel/framework/src/Illuminate/Container/Container.php"
line: 1038
message: "Target [Lcobucci\JWT\Parser] is not instantiable while building [Laravel\Passport\PersonalAccessTokenFactory]."
trace: [,…]
Login Controller Method:
public function login(Request $request) {
$login = $request->validate([
'email' => 'required:string',
'password' => 'required:string'
]);
if(filter_var($request->email, FILTER_VALIDATE_EMAIL)) {
//user sent their email
Auth::attempt(['email' => $request->email, 'password' => $request->password]);
} else {
//they sent their username instead
Auth::attempt(['username' => $request->email, 'password' => $request->password]);
}
if(!Auth::check()) {
return response([
'status' => 'fail',
'message' => 'Invalid credentials'
]);
}
$accessToken = Auth::user()
->createToken('authToken')
->accessToken;
return response([
'status' => 'success',
'user' => new User_Resource(Auth::user()),
'access_token' => $accessToken
]);
}

I encountered the same issue as well, in your project composer.json add "lcobucci/jwt": "3.3.3" and execute composer update.
I found this solution on: https://github.com/laravel/passport/issues/1381.

Laravel : "8" and Lcobucci\JWT : "^3.4"
Solution:
use Lcobucci\JWT\Encoding\JoseEncoder;
use Lcobucci\JWT\Token\Parser;
.
.
...
public function GetTokenId(Request $request)
{
// Get the Access_Token from the request
$Token = $request->bearerToken();
// Parse the Access_Token to get the claims from them the jti(Json Token Id)
$TokenId = (new Parser(new JoseEncoder()))->parse($token)->claims()
->all()['jti'];
return $tokenId;
}

if anyone still getting this error that's because $verifiedIdToken->getClaim('sub') has been deprecated in 3.4 and removed in 4.0.
use $verifiedIdToken->claims()->get('sub') this insted.

Related

Problem with Laravel, GuzzleHttp Request and Cloud9

I am trying to implement GuzzleHttp Application in my React/Laravel App.
This is my Routes:
This is my Controller Code:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class AuthController extends Controller
{
public function login(Request $request){
$http = new \GuzzleHttp\Client;
try {
$response = $http->post(route('passport.token'), [
'form_params' => [
'grant_type' => 'password',
'client_id' => config('gocv.passport.client_id'),
'client_secret' => config('gocv.passport.client_secret'),
'username' => $request->username,
'password' => $request->password,
],
'headers' => [
// 'User-Agent' => 'testing/1.0',
'Accept' => 'application/json'
]
]);
return $response->getBody();
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
if($e->getCode() == 400)
{
return response()->json('Invalid Request. Please Eneter username and password', $e->getCode());
}
else if($e->getCode() == 401)
{
return response()->json('Invalid Credentials', $e->getCode());
}
return response()->json('Something Went Wrong', $e->getCode());
}
}
}
This is my Postman Request:
When I am trying to do Post Request on this route: (api/login) it does not return any response. server just stops working and I need to restart it.
Enviroment is AWS Cloud9, php version 7.2 and laravel version 5.7 running with only php artisan serve --port=8082 --host=0.0.0.0
Note: when I send get request on other site ex: github.com it returns response. the problem is when I am trying to do request on same IP.
PS. when I try to login on route /oauth/token it works and returns token
Any answer will be apreciated . Thanks.

MethodNotAllowedHttpException in Laravel, Request::isMethod('') not working

Disclaimer: There are already some solutions in other questions which are not at all working for me. That's why I'm writing this question. I checked solutions here... StackOverflow link
I'm getting this error...
I know why its happening: It is expecting POST request but I'm offering a GET request which ruins the game. But, what I want is to show an error message when GET request is made at /api/register
What I did to stop this:
AuthController#register
public function register(Request $request)
{
$method = $request->method();
if ($method != 'POST'){
return response()->json(['status' => 'error', 'message' => 'Method not Allowed.'], 405);
}
try{
$user_registered = User::create([
'fname' => $request->fname,
'lname' => $request->lname,
'email' => $request->email,
'password' => Hash::make($request->password),
'verificationToken' => str_random(100),
'status' => 'STARTER',
'api_token' => str_random(100)
]);
$user = User::find($user_registered->id);
} catch(\Exception $e){
return response()->json(['status' => 'error', 'message' => 'User cannot be registered due to illegal or incomplete entry.'], 401);
}
return response()->json(['status' => 'success', 'user' => $user], 200);
}
So you see I'm using an if statement to check what method is used. But its still not working.
Here's my routes/api.php file:
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
Route::post('/register', 'AuthController#register');
Please help me with this.
Thanks in advance.
Did you try to add a new route instead?
Route::get('/register', function () {
return response()->json(['status' => 'error', 'message' => 'Method not Allowed.'], 405);
});
Use Laravel any route method which accepts all HTTP requests, here is you code looks like
Route::any('/register', 'AuthController#register');
Hope it helps.

Multi Jwt Auth with Laravel and Mongodb

I have three types of Authenticatable model and I need to have separate JWT authentication for each. Let me explain more about my issue.
I'm using MongoDB as my database and Laravel MongoDB is the package that I use.
User, Admin, and ServiceProvider are my models.
To having JWT auth in Laravel I use jwt-auth package. It's ok with user model (collection). when I want to use JWT with any of other models It not work and do everything with user again.
I search a lot an I found out that to change the provider user model I can use Config::set(); method like below,
Config::set('jwt.user', Admin::class);
Config::set('auth.providers.users.model', Admin::class);
But no effect on JWT auth. (I checked the value of 'jwt.user' and 'auth.providers.users.model' with Config::get() method and returned it, It has been changed to 'App\Admin').
Need to say, My codes are as simple as possible according to the documentation of the package.
Here is my UserController code:
class UserController extends Controller
{
public function login(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email|max:255',
'password' => 'required|min:6'
]);
if ($validator->fails()) {
return response()->json($validator->errors());
}
$credentials = $request->only('email', 'password');
try {
if (!$token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
return response()->json(['error' => 'could_not_create_token'], 500);
}
$user = User::where('email', $request->email)->first();
return response()->json([
'user' => $user,
'token' => $token
]);
}
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email|max:255|unique:users',
'phone' => 'required|valid_phone|unique:users',
'password' => 'required|min:6',
'first_name' => 'required',
'last_name' => 'required',
]);
if ($validator->fails()) {
return response()->json($validator->errors());
}
User::create([
'phone' => $request->get('phone'),
'first_name' => $request->get('first_name'),
'last_name' => $request->get('last_name'),
'city_abbr' => $request->get('city_abbr'),
'email' => $request->get('email'),
'password' => bcrypt($request->get('password')),
]);
$user = User::first();
$token = JWTAuth::fromUser($user);
return response()->json([
'user' => $user,
'token' => $token
]);
}
}
And my AdminController:
class AdminController extends Controller
{
public function login(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email|max:255',
'password' => 'required|min:6'
]);
if ($validator->fails()) {
return response()->json($validator->errors());
}
$credentials = $request->only('email', 'password');
Config::set('jwt.user', Admin::class);
Config::set('auth.providers.users.model', Admin::class);
try {
if (!$token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
return response()->json(['error' => 'could_not_create_token'], 500);
}
$admin = Admin::where('email', $request->email)->first();
return response()->json([
'admin' => $admin,
'token' => $token
]);
}
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email|max:255|unique:admins',
'phone' => 'required|valid_phone|unique:admins',
'password' => 'required|min:6',
'name' => 'required',
]);
if ($validator->fails()) {
return response()->json($validator->errors());
}
$admin = Admin::create([
'phone' => $request->get('phone'),
'name' => $request->get('name'),
'access' => $request->get('access'),
'email' => $request->get('email'),
'password' => bcrypt($request->get('password')),
]);
Config::set('jwt.user', Admin::class);
Config::set('auth.providers.users.model', Admin::class);
$token = JWTAuth::fromUser($admin);
return response()->json([
'admin' => $admin,
'token' => $token
]);
}
}
Am I wrong in somewhere?
Is there any solution for this?
Update:
To be sure about MongoDB functionality, I test all of above doings with a relational database, actually MySQL. Nothing changed!
JWTAuth generates token but when I run toUser method with any models except User, it returns null!
Any solution will be appreciated.
Here is what you must fo to add multi auth ability with JWT to my project.
In tymon JWT auth package. In JWTAuthServiceProvider, Change Tymon\JWTAuth\JWTAuth and Tymon\JWTAuth\Providers\User\UserInterface definition type from singleton to bind in bootBindings method.
Defined a new middleware and below code is its handle method:
public function handle($request, Closure $next){
if (!$request->header('Auth-Type')) {
return response()->json([
'success' => 0,
'result' => 'auth type could not found!'
]);
}
switch ($request->header('Auth-Type')) {
case 'user':
$auth_class = 'App\User';
break;
case 'admin':
$auth_class = 'App\Admin';
break;
case 'provider':
$auth_class = 'App\ServiceProvider';
break;
default:
$auth_class = 'App\User';
}
if (!Helpers::modifyJWTAuthUser($auth_class))
return response()->json([
'status' => 0,
'error' => 'provider not found!'
]);
return $next($request); }
Defined a function with name modifyJWTAuthUser in Helpers and here is its inner:
public static function modifyJWTAuthUser($user_class){
if (!$user_class ||
(
$user_class != 'App\User' &&
$user_class != 'App\Admin' &&
$user_class != 'App\ServiceProvider'
))
return false;
try {
Config::set('jwt.user', $user_class);
Config::set('auth.providers.users.model', $user_class);
app()->make('tymon.jwt.provider.user');
return true;
} catch (\Exception $e) {
return false;
} }
Introduced another $routeMiddleware like below in Kernel.php:
...
'modify.jwt.auth.user' => ChangeJWTAuthUser::class,
and the last step, Adding 'modify.jwt.auth.user' middleware to the routes that you want.
But even with this steps, You must have encountered a new issue. It was about getting the auth token by credentials in login and getting auth user from the token. (It seems that changing config value not effect on JWTAuth::attempt($credentials) and $this->auth->authenticate($token))
To solve the getting auth user from the token issue:
Create a new middleware CustomGetUserFromTokenwhich extends of Tymon'sjwt.authmiddleware, I meanGetUserFromTokenand in line 35, and **replace**$user = $this->auth->authenticate($token);with$user = JWTAuth::toUser($token);`
And to solve getting the auth token by credentials in login issue:
At first, Find the auth user and after that, check the user existence and valid the password with Hash::check() method, if these conditions return true, Generate a token from the user. Here is login code:
$admin = Admin::where('email', $request->email)->first();
if (!$admin || !Hash::check($request->get('password'), $admin->password)) {
return response()->json([
'success' => '0',
'error' => 'invalid_credentials'
], 401);
}
I'm not sure about this way but I think it's true until finding a correct way to do!
Conclusion:
Having multi JWT auth ability in Laravel perhaps have many other ways to do but I did like this and shared it to be helpful.
I think the only important point of this issue was app()->make('tymon.jwt.provider.user');, the ability to remake user provider after config values change.
Any other solutions will be appreciated.
You should use just one model (actually table) for authentication. When you save user and admin you can handle it. But when a user has request with jwt token, you cann't know which model will return (Admin or User)?
Use only User model for authentication and Admin model extends from User.
Redesign database like this:
users table : id, email, password, is_admin
user_details table : id, user_id, first_name, last_name, city_abbr, phone
admin_details table: id, user_id, name, phone
Put this your Admin Model for overriding all queries:
protected $table = "users";
public function newQuery()
{
return parent::newQuery()
->where("is_admin", true);
}

Auth::attempt() always returns false for default brand new installation

I tried lot to search about the problem. I couldn't find any solution. Please help me to understand what i am doing wrong.
I am attaching the code:
UserController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
use Illuminate\Support\Facades\Auth;
class UserController extends Controller
{
public function signup(Request $request){
$this->validate($request,[
'name' => 'required',
'email' => 'required|unique:users',
'password' => 'required'
]);
$user = new User([
'name' => $request->input('name'),
'email' => $request->input('email'),
'password' => bcrypt($request->input('password ')),
]);
$user->save();
return response()->json([
'state' => 'success',
'message' => 'User created.'
],201);
}
public function signin(Request $request){
$credentials = $request->only('email', 'password');
dd(Auth::attempt($credentials));
if (!$token = $this->guard()->attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $this->respondWithToken($token);
}
}
And i have routes in api.php
Route::prefix('user')->group(function () {
Route::post('signup', 'UserController#signup');
Route::post('signin', 'UserController#signin');
});
I have
I have this in database
I sent the below json to signup first, but then when i sent to signin i am getting failed.
{
"name":"ironman",
"email":"ironman#yahoo.com",
"password":"avengers"
}
This is a brand new installation of laravel 5.4 (same with 5.5), Using detailt User migration and model came with it.
When i tried to diagnose the problem myself, i found that the password_very is returning false all the time in Auth package.
I am using default password field, hashing it while creating users as other similar questions answered.
I am using php artisan serv.
I am using postman to send this request.
Please help,
This is pulling null from the request:
$request->input('password '); // notice the space
'password' => bcrypt($request->input('password ')),
You probably did not intend to put a space at the end of the input name:
$request->input('password'); // no space
'password' => bcrypt($request->input('password')),

Correct response is returned only after second attempt while generating JWT

I am trying to use Socialite and JWT together, however I am facing with some issues.
My goal is to update user's profile_image_url field in database if user already exists and give him token, if user doesn't exist, then create it and also give him token.
This is what I am doing right now:
public function handleProviderCallback(Request $request){
try{
$providerUser = Socialite::driver('facebook')->stateless()->userFromToken($request->fb_token);
$user = User::query()->firstOrNew(['email' => $providerUser->getEmail()]);
}catch(Exception $e){
return new JsonResponse(['status' => 'error', 'message' => 'Woops, some error happened']);
}
if(!$user->exists){
$user->name = $providerUser->getName();
$user->profile_image_url = $providerUser->getAvatar();
$user = $user->save();
}else{
$user->update(['profile_image_url' => $providerUser->getAvatar()]);
}
$token = JWTAuth::fromUser($user);
return $this->onAuthorized($token, $user);
}
And this is what I am returning onAuthorized:
protected function onAuthorized($token, $user){
return new JsonResponse([
'status' => '40002',
'message' => 'Successfully logged in with facebook',
'user' => [
'user_id' => $user->id,
'name' => $user->name,
'email' => $user->email,
'profile_image_url' => $user->profile_image_url,
'token' => $token
]
]);
}
But this gives me the following error on first try if user doesn't exist, even tho it saves the user into the database:
Type error: Argument 1 passed to Tymon\JWTAuth\JWT::fromUser() must
implement interface Tymon\JWTAuth\Contracts\JWTSubject, boolean given,
called in
/var/www/goodzapp.com/api/vendor/illuminate/support/Facades/Facade.php
on line 221
What I am doing wrong? Can someone please explain me. Any help would be much appreciated.

Categories