Reputation: 1186
In Laravel 9, I am trying to hit the login API with the custom guard client
, I am getting the following error. Please help.
BadMethodCallException: Method Laravel\Passport\Guards\TokenGuard::attempt does not exist.
config/Auth.php
'guards' => [
...
'client' => [
'driver' => 'passport',
'provider' => 'client',
],
],
'providers' => [
...
'client' => [
'driver' => 'eloquent',
'model' => App\Models\Client::class,
],
],
Error line: if(!$authGuard->attempt($login)){
api/AuthController.php
public function login(Request $request){
$login = $request->validate([
'email' => 'required|string',
'password' => 'required|string',
]);
try {
$authGuard = Auth::guard('client');
if(!$authGuard->attempt($login)){
$data = 'Invalid Login Credentials';
$code = 401;
} else {
$user = $authGuard->user();
$token = $user->createToken('user')->accessToken;
$code = 200;
$data = [
'user' => $user,
'token' => $token,
];
}
} catch (Exception $e) {
$data = ['error' => $e->getMessage()];
}
return response()->json($data, $code);
}
Models/Client.php
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Passport\HasApiTokens;
class Client extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
Upvotes: 6
Views: 9590
Reputation: 21
You need to add Auth::shouldUse('web'); before calling attempt methods if you are using non-default guard.
Auth::shouldUse('web');
if (Auth::attempt($request->validated())){
//your logic
}
Upvotes: 2
Reputation: 143
it seems that Laravel Passport doesn't support this type of authentication style, what I did to solve this was a bit weird but it works. I made one endpoint for all user model types like this :
Route::post('auth/{user_type}/login', [AuthController::class, 'login']);
Then I added a helper function to get the user model I wished to authenticate against :
function resolve_user_type(string $user_type)
{
return match ($user_type) {
'user'=> User::class,
'admin'=> Admin::class,
default => throw new InvalidArgumentException()
};
}
then I modified your login method like this :
public function login(Request $request , $user_type)
{
$model = resolve_user_type($user_type);
$login = $request->validate([
'email' => 'required|email',
'password' => 'required|string',
]);
try {
$user = $model::whereEmail($login['email'])->first();
if (!$user || !Hash::check($login['password'], $user->password)) {
$data = 'Invalid Login Credentials';
$code = 401;
} else {
$token = $user->createToken('authToken', [$user_type])->accessToken;
$code = 200;
$data = [
'user' => $user,
'token' => $token,
];
}
} catch (Exception $e) {
$data = ['error' => $e->getMessage()];
}
return response()->json($data, $code);
}
where the second parameter in the method createToken() was the name of the scope I created for the user token and defined it in the AuthServiceProvider file in the boot method :
Passport::tokensCan([
'user'=>'user',
'admin'=>'admin'
]);
this was dynamic enough for me to use and move on, but remember these three must be the same :
Upvotes: 0
Reputation: 1186
I solved it by changing the driver from passport
to session
in config/auth.php
'clients' => [
'driver' => 'session',
'provider' => 'clients',
],
I am not sure this is the correct solution, but it works.
Please feel free to post the answer if there is any better solution
Thanks
Upvotes: 1
Reputation: 64
attempt() is only available to guards implementing the StatefulGuard interface.
So i agree with John that attempt is not compatible with Passport.
You can try this it should work :
auth()->guard('client')->setUser($login);
or Auth::guard('client')->setUser($login);
Upvotes: 2
Reputation: 74
I think Auth::attempt()
is not compatible with passport.
So, you can use Auth::check()
method instead.
Upvotes: 2