socialiteproviders/manager
Extends Laravel Socialite with a manager to add new OAuth providers, override existing ones, and defer provider loading until needed. Supports Lumen, optional stateless mode, dynamic config overrides, and reads credentials directly from .env.
composer require socialiteproviders/manager
php artisan vendor:publish --provider="SocialiteProviders\Manager\ManagerServiceProvider"
config/services.php:
'providers' => [
'github' => [
'client_id' => env('GITHUB_CLIENT_ID'),
'client_secret' => env('GITHUB_CLIENT_SECRET'),
'redirect' => env('GITHUB_REDIRECT_URI'),
],
'custom-provider' => [
'client_id' => env('CUSTOM_CLIENT_ID'),
'client_secret' => env('CUSTOM_CLIENT_SECRET'),
'redirect' => env('CUSTOM_REDIRECT_URI'),
],
],
use Laravel\Socialite\Facades\Socialite;
$user = Socialite::driver('github')->user();
config/services.php under the providers key.Route::get('/auth/custom-provider', function () {
return Socialite::driver('custom-provider')->redirect();
});
Event-Based Extension:
Create a listener for SocialiteWasCalled to dynamically extend Socialite:
// app/Providers/EventServiceProvider.php
protected $listen = [
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
\App\Listeners\ExtendSocialite::class,
],
];
// app/Listeners/ExtendSocialite.php
public function handle(SocialiteWasCalled $socialiteWasCalled) {
$socialiteWasCalled->extendSocialite('custom-provider', \App\Providers\CustomProvider::class);
}
Dynamic Config Overrides: Override provider config at runtime (e.g., per-tenant or environment-specific):
$config = new \SocialiteProviders\Manager\Config(
env('CUSTOM_CLIENT_ID'),
env('CUSTOM_CLIENT_SECRET'),
route('custom-provider.callback'),
['scope' => ['read:user', 'write:org']]
);
Socialite::driver('custom-provider')->setConfig($config)->redirect();
Stateless Mode: Enable stateless mode for Lumen or performance-critical apps:
Socialite::stateless()->driver('github')->user();
$tenantConfig = Tenant::find($tenantId)->provider_config;
$config = new \SocialiteProviders\Manager\Config(
$tenantConfig['client_id'],
$tenantConfig['client_secret'],
route('tenant.callback', $tenantId)
);
Socialite::driver('github')->setConfig($config)->redirect();
$provider = request()->user()->isInSegment('experiment')
? 'discord'
: 'github';
Socialite::driver($provider)->redirect();
AbstractProvider to expose full OAuth response:
// In your custom provider class
public function getAccessTokenResponseBody() {
return $this->response->getBody();
}
Access it via:
$user = Socialite::driver('custom-provider')->user();
$refreshToken = $user->accessTokenResponseBody['refresh_token'];
Create a New Provider:
\SocialiteProviders\Manager\OAuth2\AbstractProvider (for OAuth2) or \SocialiteProviders\Manager\OAuth1\AbstractProvider (for OAuth1).getAuthUrl(), getAccessToken(), and getUserByToken().namespace App\Providers;
use SocialiteProviders\Manager\OAuth2\AbstractProvider;
class CustomProvider extends AbstractProvider {
protected $scopes = ['read', 'write'];
public function getAuthUrl($state) {
return $this->buildAuthUrlFromBaseUrlWithScopes('https://custom-api.com/oauth/authorize', $state);
}
public function getAccessToken($code) {
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
'form_params' => [
'code' => $code,
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret,
'redirect_uri' => $this->redirectUrl,
'grant_type' => 'authorization_code',
],
]);
return json_decode($response->getBody(), true);
}
public function getUserByToken($token) {
$response = $this->getHttpClient()->get('https://custom-api.com/api/user', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
return json_decode($response->getBody(), true);
}
}
Override Built-in Providers:
facebook). The manager will automatically use your custom implementation.Event Listener Timing:
SocialiteWasCalled listener is registered in EventServiceProvider. If not, custom providers won’t load.$listen array and the event is dispatched (it is by default in the manager).Config Precedence:
setConfig() overrides .env values. If you need .env to take precedence, avoid calling setConfig().setConfig() only for dynamic overrides (e.g., per-tenant or environment-specific settings).Stateless Mode Quirks:
Provider Naming Conflicts:
facebook), ensure your class name matches exactly (e.g., FacebookProvider). Mismatches will fall back to the default.OAuth1 vs. OAuth2:
Server class). Refer to existing OAuth1 providers (e.g., Twitter) for examples.AbstractProvider for OAuth2 and AbstractServer for OAuth1.Access Token Response Body:
AbstractProvider and implement getAccessTokenResponseBody() if needed.public function getAccessTokenResponseBody() {
return $this->tokenResponse;
}
Laravel Version Compatibility:
v3.x of the manager.composer why-not socialiteproviders/manager to verify compatibility.Provider Not Loading:
SocialiteWasCalled event is fired. Add a temporary listener:
public function handle(SocialiteWasCalled $event) {
\Log::info('Socialite called for driver: ' . $event->driver);
}
Config Issues:
dd($config) to inspect the config object before calling setConfig()..env variables are loaded (e.g., php artisan config:clear if testing locally).OAuth Errors:
$client = new \GuzzleHttp\Client([
'debug' => fopen('guzzle.log', 'w'),
]);
$provider->setHttpClient($client);
400 Bad Request).Performance Bottlenecks:
static $instances = [];
if (!isset($instances[$driver])) {
$instances[$driver] = Socialite::driver($driver);
}
return $
How can I help you explore Laravel packages today?