Socialite performs OAuth redirects and returns provider identity; your application owns account linking, session security and recovery. Configure environment-specific callback URLs and use the current provider documentation for console clicks, which change more often than code.
<?php
declare(strict_types=1);
return [
'google' => ['client_id' => env('GOOGLE_CLIENT_ID'), 'client_secret' => env('GOOGLE_CLIENT_SECRET'), 'redirect' => env('GOOGLE_REDIRECT_URI')],
'facebook' => ['client_id' => env('FACEBOOK_CLIENT_ID'), 'client_secret' => env('FACEBOOK_CLIENT_SECRET'), 'redirect' => env('FACEBOOK_REDIRECT_URI'), 'graph_version' => env('FACEBOOK_GRAPH_VERSION', 'v24.0')],
];
At callback, match the immutable provider ID first. An email can be absent, changed or already owned by a password account, so account linking needs an authenticated confirmation path. If your schema requires a password for a social-only user, generate it rather than using a predictable placeholder.
<?php
declare(strict_types=1);
use Illuminate\Support\Str;
$user = User::query()->firstOrCreate(
['email' => $providerUser->getEmail()],
['name' => $providerUser->getName() ?? 'New user', 'password' => Str::password(40)],
);
Store provider tokens encrypted only when a later provider API call needs them; request minimum scopes and provide disconnect plus another sign-in method before removing the last identity. Validate the OAuth state, preserve CSRF middleware, rate-limit entry points and log provider failures without tokens.
Model an identity separately from the user
An email is not a provider identifier. Store the immutable provider subject in an identity table with a unique composite key. It supports multiple providers, an email change and an explicit linking flow without guessing ownership.
<?php
declare(strict_types=1);
use Illuminate\\Database\\Migrations\\Migration;
use Illuminate\\Database\\Schema\\Blueprint;
use Illuminate\\Support\\Facades\\Schema;
return new class extends Migration {
public function up(): void
{
Schema::create('social_identities', function (Blueprint $table): void {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->string('provider');
$table->string('provider_id');
$table->text('access_token')->nullable();
$table->timestamps();
$table->unique(['provider', 'provider_id']);
});
}
};
Keep callback decisions explicit
The redirect uses Socialite's stateful driver. At callback, look up the provider
ID first; only an already authenticated user may attach a new identity. If a
provider gives no verified email, show an account-completion flow rather than
silently merging it with an existing account. Generate a password with
Str::password() only where the schema still requires one, and create the
application profile through the same UserObserver path as other users.
<?php
declare(strict_types=1);
namespace App\\Http\\Controllers\\Auth;
use Illuminate\\Http\\RedirectResponse;
use Laravel\\Socialite\\Facades\\Socialite;
final class SocialLoginController
{
public function redirect(string $provider): RedirectResponse
{
return Socialite::driver($provider)->redirect();
}
}
Tokens, recovery and test boundary
Encrypt tokens only when a later provider API call genuinely needs them; request
the smallest scopes, never log tokens, provide disconnect and retain another
recovery method before deleting the last identity. Use Socialite::fake() for
feature tests of acceptance, cancellation, missing email and an existing
password account. Pin a currently supported Meta Graph API version in config
and review Meta's deprecation schedule during dependency maintenance.
Appendix: provider-console checklist
Create a web OAuth client, register the exact HTTPS callback URL for each environment, publish only scopes the feature needs, then test cancellation, denied consent, an existing password account and a provider without an email. Facebook Graph API versions are retired on a schedule: pin a currently supported version in config and plan its upgrade from Meta's changelog.
When not to use social login
Do not make a social provider the only recovery route for a business account. Do not auto-link an unverified email. For enterprise SSO, use OIDC/SAML with domain and lifecycle controls rather than treating consumer OAuth as employee identity.