socialiteproviders/instagram
Instagram OAuth provider for Laravel Socialite. Lets users log in with Instagram and returns a Socialite user object. Install via Composer, configure your client ID and secret, then add the provider to Socialite config and redirect/callback routes.
Install the split package (it pulls in socialiteproviders/manager automatically):
composer require socialiteproviders/instagram
Register the provider's listener so Socialite learns the instagram driver. On Laravel 10 and below, add it to app/Providers/EventServiceProvider.php:
protected $listen = [
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
\SocialiteProviders\Instagram\InstagramExtendSocialite::class.'@handle',
],
];
On Laravel 11+ there is no EventServiceProvider by default, so register it in AppServiceProvider::boot():
use Illuminate\Support\Facades\Event;
use SocialiteProviders\Manager\SocialiteWasCalled;
Event::listen(function (SocialiteWasCalled $event) {
$event->extendSocialite('instagram', \SocialiteProviders\Instagram\Provider::class);
});
Add credentials to config/services.php and .env:
'instagram' => [
'client_id' => env('INSTAGRAM_CLIENT_ID'),
'client_secret' => env('INSTAGRAM_CLIENT_SECRET'),
'redirect' => env('INSTAGRAM_REDIRECT_URI'),
],
Where to look first: the docs at socialiteproviders.com/Instagram and the provider class itself at vendor/socialiteproviders/instagram/src/Provider.php — it is small and tells you exactly which endpoints, scopes, and user fields you are getting.
First use case — the classic "Log in with Instagram" button. Two routes, one controller method each:
Route::get('/auth/instagram', fn () => Socialite::driver('instagram')->redirect());
Route::get('/auth/instagram/callback', [InstagramController::class, 'callback']);
public function callback()
{
$ig = Socialite::driver('instagram')->user();
// $ig->getId(), ->getNickname(), ->getName(), ->getAvatar(), ->token
Auth::login(User::firstOrCreateFromInstagram($ig));
return redirect()->intended('/dashboard');
}
Separate "login" from "connect". Use two entry routes — one that authenticates a new/returning user, one that attaches an Instagram account to an already-authenticated user — and branch on Auth::check() inside the callback. This is the cleanest way to support both flows with one provider.
Persist tokens, not just the user. Instagram tokens expire, so store them on a social_accounts table keyed by (provider, provider_id) and keep token, refresh_token, and expires_at. This makes re-login, unlinking, and background refresh possible later:
$account = SocialAccount::updateOrCreate(
['provider' => 'instagram', 'provider_id' => $ig->getId()],
[
'user_id' => $user->id,
'nickname' => $ig->getNickname(),
'avatar' => $ig->getAvatar(),
'token' => $ig->token,
'refresh_token' => $ig->refreshToken,
'expires_at' => $ig->expiresIn ? now()->addSeconds($ig->expiresIn) : null,
]
);
Stateless mode for mobile/SPA. When the client already obtained an access token, skip the redirect/state dance:
$ig = Socialite::driver('instagram')->stateless()->userFromToken($request->token);
Handle the error branch. Instagram redirects back with ?error=access_denied&error_description=... when the user cancels — check $request->has('error') before calling ->user(), otherwise you get an unhelpful exception.
Testing. Mock the Socialite driver rather than hitting the network:
$mock = Mockery::mock(\Laravel\Socialite\Contracts\Provider::class);
$mock->shouldReceive('user')->andReturn($socialiteUser);
Socialite::shouldReceive('driver')->with('instagram')->andReturn($mock);
Wrap the callback in a try/catch for InvalidStateException and redirect the user back to the login page. State mismatches are common in production and should not produce a 500.
Socialite::driver('instagram') throws Driver [instagram] is not supported. This is the #1 install mistake.services.php. php artisan config:cache stale caches are the #2 cause of "missing client_id" errors.$ig->getEmail() is usually null. Plan your user-creation flow accordingly — either require email post-signup or generate a placeholder.services.php must match the URI registered in the Meta app dashboard character-for-character — scheme, host, port, trailing slash. Facebook/Meta requires HTTPS for production callbacks.SESSION_DOMAIN mismatches, and proxy/CDN hostname differences all produce InvalidStateException. Stateless mode avoids this entirely where appropriate.user_profile, user_media) require Meta App Review before they work in production. Set defaults via ->scopes([...]) or a 'scopes' config key.token/expiresIn but does not refresh for you — schedule a refresh job and store expires_at.getAuthUrl()/getTokenUrl() in a subclass.getAvatar() may return a time-limited CDN URL or null; download and re-host it if you display it long-term.$ig->getRaw() returns the full API response array — invaluable when a field you expect is missing or renamed.SocialiteProviders\Instagram\Provider and override mapUserToObject(), getAuthUrl(), or getTokenUrl() if you need custom scopes, endpoint versions, or extra fields. Register your subclass instead of the vendor one in the event listener.How can I help you explore Laravel packages today?