Ok, I might have been carried over by my response on the other thread that was posted on a very close time.
So let's add a custom user provider.
Step 1 - Create a custom user provider
Create the class below in your project.
Please read the comments in the code carefully.
<?php
namespace App;
use Illuminate\Auth\GenericUser;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Support\Facades\Http;
class ExternalApiUserProvider implements UserProvider
{
public function retrieveById($identifier)
{
// This method is called from subsequent calls until the session expires.
//
// As you don't have a local users database we are going
// to assume the identifier saved into the session is fine.
//
// Session cookies are encrypted by default
//
// This avoid calling the external service on every navigation.
//
// The downside is that if the user is not authorized anymore
// in the external service, you won't know until their session expires.
//
// Ideally you should set a lower session duration so user
// gets logged out quickier.
//
// An alternative is to save encrypted the user's credentials
// and call the external service every time.
//
// But that would make a external API call on every request,
// making your app slower. But is the most secure way.
//
// If you want I can make an modified version exemplifying
// how you could do this.
return new GenericUser([
'id' => $identifier,
'email' => $identifier,
]);
}
public function retrieveByToken($identifier, $token)
{
return null;
}
public function updateRememberToken(Authenticatable $user, $token)
{
}
public function retrieveByCredentials(array $credentials)
{
if (! array_key_exists('email', $credentials)) {
return null;
}
// GenericUser is a class from Laravel Auth System
return new GenericUser([
'id' => $credentials['email'],
'email' => $credentials['email'],
]);
}
public function validateCredentials(Authenticatable $user, array $credentials)
{
if (! array_key_exists('password', $credentials)) {
return false;
}
// This is a simplified usage of Laravel's HTTP Client to call the external API
// You might need to send more info to the external service.
// Please refer to the HTTP Client docs to learn how to use it properly.
$response = Http::post('https://example.com/authenticate', [
// $user is the GenericUser instance created in
// the retrieveByCredentials() method above.
'email' => $user->email,
'password' => $credentials['password'],
]);
return $response->ok();
}
}
HTTP Client docs: https://laravel.com/docs/8.x/http-client
Step 2 - Register the User Provider with the Auth Manager
Add this to your app's AuthServiceProvider's boot method:
<?php
namespace App\Providers;
use App\ExternalApiUserProvider;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
// 'App\Models\Model' => 'App\Policies\ModelPolicy',
];
public function boot()
{
$this->registerPolicies();
// you can choose a different name
Auth::provider('external', function ($app, array $config) {
return new ExternalApiUserProvider();
});
}
}
Step 3 - Configure ./config/auth.php
<?php
return [
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'external', // <<< CHANGED HERE
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
/// ADDED here
'external' => [
'driver' => 'external',
],
],
// ... keep the other configs
];
Step 4 - CustomLoginController@doLogin
On first login you should call Auth::attempt() instead of Auth::check().
Auth::check() is meant to be used after a user is already logged in.
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Auth;
class CustomLoginController extends Controller
{
// ... other methods
public function doLogin()
{
if (Auth::attempt(request()->only('email', 'password'))) {
return redirect('secret');
}
return back()->withErrors([
'email' => 'invalid credentials',
]);
}
}
Step 5 - Guard the secret route
Don't forget to guard the secret route:
Route::get('/secret', [SecretController::class, 'show'])->middeware('auth');
Hope this helps.