Laravel Socialite
Com implementar login social amb Laravel Socialite: Google, GitHub, Facebook, OAuth, gestió d'usuaris i providers personalitzats.
Que es Laravel Socialite?#
Laravel Socialite es un paquet oficial que simplifica enormement la implementacio de login social a les aplicacions Laravel. En lloc de gestionar manualment el flux OAuth2 amb cada proveidor (Google, GitHub, Facebook, etc.), Socialite proporciona una interficie expressiva i unificada que abstrau tota la complexitat del protocol.
El login social es una funcionalitat cada vegada mes important a les aplicacions web modernes. Des del punt de vista de l'experiencia d'usuari, elimina la friccio del registre: en lloc d'omplir formularis i recordar contrasenyes, l'usuari pot accedir amb un sol clic. Aixo te un impacte directe en les taxes de conversio, ja que redueix drasricament l'abandono durant el proces de registre. A mes, des del punt de vista de seguretat, delegar l'autenticacio a proveidors com Google o GitHub significa que la teva aplicacio no ha de gestionar contrasenyes, reduint el risc de filtracions.
Socialite gestiona tot el flux OAuth2: la redireccio al proveidor, la recepcio del callback amb el codi d'autoritzacio, l'intercanvi per un token d'acces i la recuperacio de les dades de l'usuari. Tot aixo amb poques linies de codi.
Installacio#
Instal·la Socialite amb Composer:
composer require laravel/socialiteNo calen migracions ni publicacio de configuracio addicional per part del paquet. Socialite utilitza la configuracio existent de config/services.php per als proveidors.
Configuracio#
Cada proveidor OAuth requereix tres valors: un client ID, un client secret i una URL de callback. Aquests valors s'obtenen quan registres la teva aplicacio al panell de desenvolupadors de cada proveidor (Google Cloud Console, GitHub Developer Settings, Facebook for Developers, etc.).
Afegeix la configuracio al fitxer config/services.php:
// config/services.php
'google' => [
'client_id' => env('GOOGLE_CLIENT_ID'),
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
'redirect' => env('GOOGLE_REDIRECT_URI'),
],
'github' => [
'client_id' => env('GITHUB_CLIENT_ID'),
'client_secret' => env('GITHUB_CLIENT_SECRET'),
'redirect' => env('GITHUB_REDIRECT_URI'),
],
'facebook' => [
'client_id' => env('FACEBOOK_CLIENT_ID'),
'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
'redirect' => env('FACEBOOK_REDIRECT_URI'),
],I defineix els valors reals al fitxer .env:
GOOGLE_CLIENT_ID=123456789.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxxxxxx
GOOGLE_REDIRECT_URI=http://localhost:8000/auth/google/callback
GITHUB_CLIENT_ID=Iv1.xxxxxxxxxxxxxxxx
GITHUB_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
GITHUB_REDIRECT_URI=http://localhost:8000/auth/github/callbackMai poseu les credencials OAuth directament al codi font. Utilitzeu sempre variables d'entorn al fitxer .env i assegureu-vos que .env esta inclós al .gitignore.
El flux OAuth explicat#
El protocol OAuth2 segueix un flux de redireccio en dos passos que Socialite gestiona automaticament:
Pas 1 - Redireccio (redirect): L'usuari fa clic al boto "Inicia sessio amb Google". La teva aplicacio redirigeix l'usuari al proveidor OAuth (Google, GitHub, etc.) amb els parametres necessaris: el client ID, els permisos sol·licitats (scopes) i la URL de retorn. El proveidor mostra la pantalla de consentiment on l'usuari autoritza l'acces.
Pas 2 - Callback: Despres que l'usuari autoritzi l'aplicacio, el proveidor redirigeix de tornada a la teva URL de callback amb un codi d'autoritzacio temporal. Socialite intercanvia automaticament aquest codi per un token d'acces i utilitza el token per obtenir les dades del perfil de l'usuari (nom, email, avatar, etc.).
Usuari → Clic "Login amb Google" → Laravel (redirect)
→ Google (pantalla consentiment) → Usuari autoritza
→ Google redirigeix al callback → Laravel rep el codi
→ Laravel intercanvia codi per token → Obte dades usuari
→ Crea/actualitza usuari → Inicia sessio
Proveidors integrats#
Socialite inclou suport natiu per a vuit proveidors populars:
- Facebook - La xarxa social mes gran del mon
- Twitter / X - Utilitza OAuth 1.0a (Socialite ho gestiona transparentment)
- LinkedIn - Ideal per a aplicacions professionals i B2B
- Google - El proveidor mes utilitzat, amb accés a l'ecosistema Google
- GitHub - Popular per a aplicacions de desenvolupadors
- GitLab - Alternativa a GitHub, tambe auto-allotjable
- Bitbucket - Integrat amb l'ecosistema Atlassian
- Slack - Per a aplicacions que integren amb espais de treball Slack
Cada proveidor segueix exactament la mateixa interficie, aixi que canviar de proveidor o afegir-ne de nous es trivial.
Implementacio completa#
Migracio per a columnes socials#
Abans de crear les rutes i el controlador, necessitem preparar la base de dades per emmagatzemar la informacio del proveidor social. Crearem una migracio que afegeixi les columnes necessaries a la taula users:
php artisan make:migration add_social_columns_to_users_table --table=usersuse Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('provider')->nullable()->after('password');
$table->string('provider_id')->nullable()->after('provider');
$table->string('avatar')->nullable()->after('provider_id');
$table->string('password')->nullable()->change();
});
}
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn(['provider', 'provider_id', 'avatar']);
$table->string('password')->nullable(false)->change();
});
}
};Fixeu-vos que fem el camp password nullable. Els usuaris que s'autentiquen exclusivament a traves d'un proveidor social no necessiten contrasenya local. Executeu la migracio:
php artisan migrateRutes#
Necessitem dues rutes per a cada proveidor: una per redirigir l'usuari al proveidor i una altra per gestionar el callback de retorn. Es bona practica parametritzar el proveidor a la ruta per reutilitzar la logica:
use App\Http\Controllers\SocialAuthController;
// Rutes per a autenticacio social
Route::get('/auth/{provider}/redirect', [SocialAuthController::class, 'redirect'])
->name('social.redirect');
Route::get('/auth/{provider}/callback', [SocialAuthController::class, 'callback'])
->name('social.callback');Controlador amb gestio d'errors#
El controlador es on resideix la logica principal. Es important gestionar correctament els errors, ja que l'usuari pot cancel·lar el proces d'autoritzacio o el proveidor pot retornar un error:
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Laravel\Socialite\Facades\Socialite;
use Laravel\Socialite\Two\InvalidStateException;
class SocialAuthController extends Controller
{
/**
* Proveidors permesos.
*/
protected array $providers = [
'google', 'github', 'facebook', 'linkedin',
];
/**
* Redirigeix l'usuari al proveidor OAuth.
*/
public function redirect(string $provider)
{
if (! in_array($provider, $this->providers)) {
abort(404, "Proveidor '{$provider}' no suportat.");
}
return Socialite::driver($provider)->redirect();
}
/**
* Gestiona el callback del proveidor OAuth.
*/
public function callback(string $provider)
{
if (! in_array($provider, $this->providers)) {
abort(404, "Proveidor '{$provider}' no suportat.");
}
try {
$socialUser = Socialite::driver($provider)->user();
} catch (InvalidStateException $e) {
Log::warning("OAuth state invalid per a {$provider}", [
'error' => $e->getMessage(),
]);
return redirect()->route('login')
->with('error', 'La sessio ha expirat. Torna-ho a provar.');
} catch (\Exception $e) {
Log::error("Error OAuth amb {$provider}", [
'error' => $e->getMessage(),
]);
return redirect()->route('login')
->with('error', 'Hi ha hagut un error amb l\'autenticacio. Torna-ho a provar.');
}
$user = $this->findOrCreateUser($socialUser, $provider);
Auth::login($user, remember: true);
return redirect()->intended('/dashboard');
}
/**
* Cerca o crea l'usuari a partir de les dades del proveidor.
*/
protected function findOrCreateUser($socialUser, string $provider): User
{
// Primer, busquem per provider + provider_id (login recurrent)
$existingUser = User::where('provider', $provider)
->where('provider_id', $socialUser->getId())
->first();
if ($existingUser) {
// Actualitzem les dades que podrien haver canviat
$existingUser->update([
'name' => $socialUser->getName(),
'avatar' => $socialUser->getAvatar(),
]);
return $existingUser;
}
// Busquem per email (l'usuari ja existeix amb registre tradicional)
$userByEmail = User::where('email', $socialUser->getEmail())->first();
if ($userByEmail) {
// Vinculem el proveidor social al compte existent
$userByEmail->update([
'provider' => $provider,
'provider_id' => $socialUser->getId(),
'avatar' => $socialUser->getAvatar(),
]);
return $userByEmail;
}
// Creem un usuari completament nou
return User::create([
'name' => $socialUser->getName(),
'email' => $socialUser->getEmail(),
'provider' => $provider,
'provider_id' => $socialUser->getId(),
'avatar' => $socialUser->getAvatar(),
]);
}
}Hi ha tres escenaris importants que el controlador gestiona:
-
Usuari recurrent: L'usuari ja s'ha autenticat previament amb el mateix proveidor. El busquem per
provider+provider_idi actualitzem les dades que podrien haver canviat (nom, avatar). -
Usuari existent amb el mateix email: L'usuari te un compte creat amb registre tradicional (email + contrasenya) i ara vol iniciar sessio amb un proveidor social que utilitza el mateix email. En aquest cas, vinculem el proveidor social al compte existent.
-
Usuari completament nou: No existeix cap compte amb el
provider_idni l'email. Creem un nou registre.
El patro updateOrCreate tambe funciona be per a casos simples, pero la logica separada permet gestionar millor l'escenari de vincular un proveidor social a un compte existent amb email coincident.
Actualitzar el model User#
Afegeix les columnes noves als $fillable del model User:
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
protected $fillable = [
'name',
'email',
'password',
'provider',
'provider_id',
'avatar',
];
protected $hidden = [
'password',
'remember_token',
];
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}Boto de login social a la vista#
A la vista de login, afegeix botons per als proveidors socials:
<!-- resources/views/auth/login.blade.php -->
<div class="mt-6">
<div class="relative">
<div class="absolute inset-0 flex items-center">
<div class="w-full border-t border-gray-300"></div>
</div>
<div class="relative flex justify-center text-sm">
<span class="bg-white px-2 text-gray-500">O continua amb</span>
</div>
</div>
<div class="mt-6 grid grid-cols-2 gap-3">
<a href="{{ route('social.redirect', 'google') }}"
class="flex items-center justify-center rounded-md border px-4 py-2 hover:bg-gray-50">
Google
</a>
<a href="{{ route('social.redirect', 'github') }}"
class="flex items-center justify-center rounded-md border px-4 py-2 hover:bg-gray-50">
GitHub
</a>
</div>
</div>L'objecte usuari de Socialite#
Quan Socialite obte les dades de l'usuari del proveidor, retorna un objecte amb una interficie consistent independentment del proveidor utilitzat. Aixo et permet treballar amb les dades de la mateixa manera tant si l'usuari ve de Google com de GitHub:
$socialUser = Socialite::driver('google')->user();
// Propietats basiques
$socialUser->getId(); // ID unic al proveidor (ex: "1234567890")
$socialUser->getName(); // Nom complet (ex: "Joan Garcia")
$socialUser->getEmail(); // Correu electronic
$socialUser->getAvatar(); // URL de la foto de perfil
$socialUser->getNickname(); // Nom d'usuari (no tots els proveidors el tenen)
// Token OAuth
$socialUser->token; // Token d'acces
$socialUser->refreshToken; // Token de refresc (si el proveidor el proporciona)
$socialUser->expiresIn; // Segons fins que el token expira
$socialUser->approvedScopes; // Scopes aprovats per l'usuari
// Dades completes del proveidor
$socialUser->getRaw(); // Array amb TOTES les dades retornades pel proveidorEl metode getRaw() es especialment util quan necessites accedir a dades especifiques del proveidor que no estan mapeades als metodes estandard. Per exemple, Google pot retornar el domini de l'organitzacio, i GitHub pot retornar el nombre de repositoris publics:
$raw = Socialite::driver('github')->user()->getRaw();
// Dades especifiques de GitHub
$bio = $raw['bio'];
$publicRepos = $raw['public_repos'];
$location = $raw['location'];
$company = $raw['company'];Scopes: sol·licitar permisos addicionals#
Per defecte, Socialite sol·licita els permisos minims necessaris per obtenir el perfil basic de l'usuari. Si la teva aplicacio necessita accedir a mes dades o realitzar accions en nom de l'usuari, pots sol·licitar scopes addicionals amb el metode scopes():
// Sol·licitar acces al calendari i al drive de Google
return Socialite::driver('google')
->scopes(['calendar.readonly', 'drive.readonly'])
->redirect();
// Sol·licitar acces als repositoris privats de GitHub
return Socialite::driver('github')
->scopes(['repo', 'read:org'])
->redirect();
// Sol·licitar permisos d'email i publicacio a Facebook
return Socialite::driver('facebook')
->scopes(['email', 'publish_actions'])
->redirect();Per defecte, scopes() afegeix els scopes nous als scopes per defecte del proveidor. Si vols substituir completament els scopes per defecte, utilitza setScopes():
// Substituir TOTS els scopes (inclosos els per defecte)
return Socialite::driver('google')
->setScopes(['openid', 'profile', 'email', 'calendar.readonly'])
->redirect();Cada proveidor te la seva propia llista de scopes disponibles. Consulteu la documentacio del proveidor per veure quins scopes podeu sol·licitar: Google Scopes, GitHub Scopes.
Parametres opcionals#
A mes dels scopes, pots passar parametres addicionals a la peticio d'autoritzacio amb el metode with(). Aquests parametres varien segons el proveidor:
// Forcar la pantalla de seleccio de compte de Google
return Socialite::driver('google')
->with(['prompt' => 'select_account'])
->redirect();
// Permetre nomes registre (no login) a Google
return Socialite::driver('google')
->with([
'prompt' => 'consent',
'access_type' => 'offline', // Per obtenir refresh token
])
->redirect();
// Especificar l'organitzacio a GitHub
return Socialite::driver('github')
->with(['login' => '', 'allow_signup' => 'false'])
->redirect();El parametre access_type => 'offline' de Google es especialment important si necessites el refreshToken. Sense aquest parametre, Google no retorna un token de refresc.
Autenticacio stateless (per a APIs i SPAs)#
El flux OAuth estandard utilitza sessions per emmagatzemar l'estat (el parametre state) entre la redireccio i el callback. Aixo protegeix contra atacs CSRF. No obstant, si la teva aplicacio es una API sense sessions (per exemple, una SPA amb Sanctum), pots desactivar la verificacio d'estat amb el metode stateless():
// Redirigir sense guardar l'estat a la sessio
return Socialite::driver('google')->stateless()->redirect();
// Al callback, tambe cal indicar stateless
$user = Socialite::driver('google')->stateless()->user();L'autenticacio stateless desactiva la proteccio CSRF del flux OAuth. Nomes utilitzeu-la quan treballeu amb APIs sense sessions. Per a aplicacions web tradicionals amb sessions, manteniu el flux estandard amb verificacio d'estat.
Aixo es util especialment quan construeixes una API que rep el token OAuth directament del frontend (per exemple, una SPA que utilitza el SDK de Google al client):
// Obtenir l'usuari a partir d'un token que ja tens
$user = Socialite::driver('google')->userFromToken($token);
// O a partir d'un token i un secret (per a OAuth 1.0a com Twitter)
$user = Socialite::driver('twitter')->userFromTokenAndSecret($token, $secret);Multiples proveidors: vincular comptes socials#
En una aplicacio real, sovint vols que els usuaris puguin vincular multiples comptes socials al seu perfil. Per exemple, un usuari que s'ha registrat amb Google pot voler vincular tambe el seu compte de GitHub. Aixo requereix una taula separada per als proveidors socials:
php artisan make:migration create_social_accounts_tablereturn new class extends Migration
{
public function up(): void
{
Schema::create('social_accounts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->string('provider');
$table->string('provider_id');
$table->string('provider_token')->nullable();
$table->string('provider_refresh_token')->nullable();
$table->timestamp('token_expires_at')->nullable();
$table->string('avatar')->nullable();
$table->timestamps();
$table->unique(['provider', 'provider_id']);
$table->unique(['user_id', 'provider']);
});
}
public function down(): void
{
Schema::dropIfExists('social_accounts');
}
};Crea el model SocialAccount:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class SocialAccount extends Model
{
protected $fillable = [
'user_id',
'provider',
'provider_id',
'provider_token',
'provider_refresh_token',
'token_expires_at',
'avatar',
];
protected function casts(): array
{
return [
'token_expires_at' => 'datetime',
];
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}I la relacio al model User:
use App\Models\SocialAccount;
use Illuminate\Database\Eloquent\Relations\HasMany;
class User extends Authenticatable
{
public function socialAccounts(): HasMany
{
return $this->hasMany(SocialAccount::class);
}
}Amb aquest esquema, el controlador de callback es modifica per treballar amb la taula de comptes socials:
protected function findOrCreateUser($socialUser, string $provider): User
{
// Buscar per compte social existent
$socialAccount = SocialAccount::where('provider', $provider)
->where('provider_id', $socialUser->getId())
->first();
if ($socialAccount) {
// Actualitzar token i avatar
$socialAccount->update([
'provider_token' => $socialUser->token,
'provider_refresh_token' => $socialUser->refreshToken,
'avatar' => $socialUser->getAvatar(),
]);
return $socialAccount->user;
}
// Si l'usuari esta autenticat, vincular el nou proveidor
if ($user = auth()->user()) {
$user->socialAccounts()->create([
'provider' => $provider,
'provider_id' => $socialUser->getId(),
'provider_token' => $socialUser->token,
'provider_refresh_token' => $socialUser->refreshToken,
'avatar' => $socialUser->getAvatar(),
]);
return $user;
}
// Buscar per email
$user = User::where('email', $socialUser->getEmail())->first();
if (! $user) {
$user = User::create([
'name' => $socialUser->getName(),
'email' => $socialUser->getEmail(),
]);
}
// Crear el compte social vinculat
$user->socialAccounts()->create([
'provider' => $provider,
'provider_id' => $socialUser->getId(),
'provider_token' => $socialUser->token,
'provider_refresh_token' => $socialUser->refreshToken,
'avatar' => $socialUser->getAvatar(),
]);
return $user;
}Proveidors de la comunitat#
A mes dels vuit proveidors integrats, la comunitat manté una extensa colleccio de proveidors addicionals al projecte Socialite Providers. Hi trobareu proveidors per a Apple, Discord, Twitch, Spotify, Dribbble, Steam, Azure, i desenes mes.
Instal·lar un proveidor de la comunitat es senzill. Per exemple, per afegir Apple Sign In:
composer require socialiteproviders/appleDespres, registra el listener d'events al fitxer AppServiceProvider (o al EventServiceProvider en versions anteriors de Laravel):
// app/Providers/AppServiceProvider.php
use SocialiteProviders\Apple\AppleExtendSocialite;
use SocialiteProviders\Manager\SocialiteWasCalled;
public function boot(): void
{
Event::listen(
SocialiteWasCalled::class,
AppleExtendSocialite::class . '@handle',
);
}Afegeix la configuracio al fitxer config/services.php seguint la documentacio de cada proveidor:
'apple' => [
'client_id' => env('APPLE_CLIENT_ID'),
'client_secret' => env('APPLE_CLIENT_SECRET'),
'redirect' => env('APPLE_REDIRECT_URI'),
],Un cop configurat, pots utilitzar el proveidor exactament com qualsevol proveidor integrat:
return Socialite::driver('apple')->redirect();Consideracions de seguretat#
La implementacio de login social te diverses implicacions de seguretat que cal tenir en compte:
Emmagatzematge de tokens#
Els tokens OAuth son credencials sensibles. Si emmagatzemes tokens d'acces a la base de dades per fer crides a l'API del proveidor en nom de l'usuari, encripta'ls:
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Support\Facades\Crypt;
class SocialAccount extends Model
{
protected function providerToken(): Attribute
{
return Attribute::make(
get: fn (?string $value) => $value ? Crypt::decryptString($value) : null,
set: fn (?string $value) => $value ? Crypt::encryptString($value) : null,
);
}
}Verificacio d'email#
Quan un usuari s'autentica a traves d'un proveidor social, l'email proporcionat pel proveidor es pot considerar verificat (Google i GitHub ja verifiquen els emails). Pots marcar automaticament l'email com a verificat:
$user = User::create([
'name' => $socialUser->getName(),
'email' => $socialUser->getEmail(),
'email_verified_at' => now(), // Verificat pel proveidor
]);Vinculacio de comptes#
Quan un usuari intenta vincular un compte social que ja esta vinculat a un altre usuari, cal gestionar-ho explicitament:
$existingAccount = SocialAccount::where('provider', $provider)
->where('provider_id', $socialUser->getId())
->first();
if ($existingAccount && $existingAccount->user_id !== auth()->id()) {
return redirect()->back()
->with('error', 'Aquest compte social ja esta vinculat a un altre usuari.');
}Testing: simular Socialite als tests#
Socialite proporciona el metode fake() per simular les respostes dels proveidors als tests, sense fer crides reals a cap API externa:
use Laravel\Socialite\Facades\Socialite;
use Laravel\Socialite\Two\User as SocialiteUser;
test('pot iniciar sessio amb github', function () {
// Crear un usuari simulat de Socialite
$socialiteUser = (new SocialiteUser)->map([
'id' => '12345',
'nickname' => 'joangarcia',
'name' => 'Joan Garcia',
'email' => 'joan@example.com',
'avatar' => 'https://example.com/avatar.jpg',
]);
$socialiteUser->token = 'fake-token';
$socialiteUser->refreshToken = 'fake-refresh-token';
$socialiteUser->expiresIn = 3600;
// Simular la resposta de Socialite
Socialite::shouldReceive('driver')
->with('github')
->andReturn(
Mockery::mock(\Laravel\Socialite\Contracts\Provider::class, function ($mock) use ($socialiteUser) {
$mock->shouldReceive('user')->andReturn($socialiteUser);
})
);
// Fer la peticio al callback
$response = $this->get('/auth/github/callback');
// Verificar que l'usuari s'ha creat i autenticat
$response->assertRedirect('/dashboard');
$this->assertDatabaseHas('users', [
'email' => 'joan@example.com',
'provider' => 'github',
'provider_id' => '12345',
]);
$this->assertAuthenticated();
});
test('vincula compte social a usuari existent amb mateix email', function () {
// Crear un usuari previ amb registre tradicional
$user = User::factory()->create([
'email' => 'joan@example.com',
'provider' => null,
'provider_id' => null,
]);
$socialiteUser = (new SocialiteUser)->map([
'id' => '12345',
'name' => 'Joan Garcia',
'email' => 'joan@example.com',
'avatar' => 'https://example.com/avatar.jpg',
]);
$socialiteUser->token = 'fake-token';
Socialite::shouldReceive('driver')
->with('google')
->andReturn(
Mockery::mock(\Laravel\Socialite\Contracts\Provider::class, function ($mock) use ($socialiteUser) {
$mock->shouldReceive('user')->andReturn($socialiteUser);
})
);
$this->get('/auth/google/callback');
// Verificar que no s'ha creat un nou usuari sino que s'ha vinculat
expect(User::count())->toBe(1);
expect($user->fresh()->provider)->toBe('google');
expect($user->fresh()->provider_id)->toBe('12345');
});
test('redirigeix al proveidor oauth', function () {
$response = $this->get('/auth/github/redirect');
$response->assertRedirectContains('github.com/login/oauth');
});Tambe pots testejar que la redireccio al proveidor inclou els scopes correctes:
test('sol·licita els scopes correctes a google', function () {
Socialite::shouldReceive('driver')
->with('google')
->andReturn(
Mockery::mock(\Laravel\Socialite\Contracts\Provider::class, function ($mock) {
$mock->shouldReceive('scopes')
->with(['calendar.readonly'])
->andReturnSelf();
$mock->shouldReceive('redirect')
->andReturn(redirect('https://accounts.google.com/'));
})
);
$response = $this->get('/auth/google/redirect');
$response->assertRedirect();
});Quan testegeu el flux complet de Socialite, assegureu-vos de simular tant el metode driver() com el metode user() o redirect(). El facade Socialite es pot mockejar facilment gracies al sistema de facades de Laravel.