Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Oauth2 Instagram Laravel Package

league/oauth2-instagram

Instagram OAuth 2.0 provider for the League OAuth2 Client. Adds Instagram authorization and token handling to PHP applications so you can authenticate users and access Instagram APIs with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

league/oauth2-instagram 3.0.0 is a breaking release: it drops the Legacy API (api.instagram.com/v1/...) and swaps the resource-owner call to the Instagram Basic Display endpoint (https://graph.instagram.com/me). If you have 2.x in a composer.lock, audit before bumping — three named getters were removed (see Gotchas).

composer require league/oauth2-instagram:^3.0

Same provider API as every other league/oauth2-client provider — instantiate from config, never inline:

use League\OAuth2\Client\Provider\Instagram;

$provider = new Instagram([
    'clientId'     => config('services.instagram.client_id'),
    'clientSecret' => config('services.instagram.client_secret'),
    'redirectUri'  => route('instagram.callback'),
    // 3.0.0: Graph host is configurable — useful when you must point at
    // graph.facebook.com instead of graph.instagram.com. Check the
    // constructor in the tagged source for the exact option key.
    // 'graphHost' => 'https://graph.facebook.com/v21.0',
]);

The canonical three-legged flow is unchanged, but note the default scope is now ['user_profile'], so a bare getAuthorizationUrl() only buys you a profile:

// 1. Redirect out
$url = $provider->getAuthorizationUrl([
    'scope' => ['user_profile'],          // add 'user_media' only if you really need media
]);
session(['ig_state' => $provider->getState()]);
return redirect($url);

// 2. Handle callback
$token = $provider->getAccessToken('authorization_code', [
    'code' => $request->query('code'),
]);

// 3. Fetch the user
$owner = $provider->getResourceOwner($token);
$owner->getId();      // Instagram-scoped user id — still present
$owner->toArray();    // ['id', 'username', 'account_type', 'media_count', 'profile_picture_url']

Read InstagramResourceOwner first. After 3.0.0 it no longer carries legacy-API fields, so anything you learned from a 2.x debug dump (name, description, website, followers_count) is gone.

Implementation Patterns

Register the provider as a singleton so credentials and the Graph host live in one place — the host option is the whole point of 3.0.0's new feature, and you do not want it duplicated across call sites:

$this->app->singleton(Instagram::class, fn () => new Instagram([
    'clientId'     => config('services.instagram.client_id'),
    'clientSecret' => config('services.instagram.client_secret'),
    'redirectUri'  => route('instagram.callback'),
    // 'graphHost' => config('services.instagram.graph_host'),
]));

Persist the token, not the provider. Store $token->getToken(), $token->getExpires(), and $token->getResourceOwnerId() alongside the $owner->getId() value on a social_accounts row.

Map the resource owner once, into your own DTO. Since the getters are thinner now, centralise the mapping instead of sprinkling toArray() keys through controllers:

$data = $owner->toArray();
InstagramProfile::from([
    'id'        => $data['id'],
    'username'  => $data['username'] ?? null,
    'avatar'    => $data['profile_picture_url'] ?? null,
    'account'   => $data['account_type'] ?? null,
]);

Call Graph yourself — this package only does OAuth. With 3.0.0 the resource-owner URL moved to the Graph host, but nothing else is wrapped:

Http::withToken($token->getToken())
    ->get('https://graph.instagram.com/me', [
        'fields' => 'id,username,account_type,media_count,profile_picture_url',
    ]);

Keep getAuthorizationUrl() and getAccessToken() as two separate service methods so each is independently unit-testable and the state round-trip is explicit.

Testing. Inject a mock HTTP client via the httpClient provider option and assert on the outgoing request — the endpoint change in 3.0.0 makes this worth doing, because a test that asserts on graph.instagram.com/me will catch the next host/format move:

$provider = new Instagram($config, ['httpClient' => new \Http\Mock\Client()]);

Integration tip: if you're on Laravel and only need login + a profile, a Socialite driver may still be the better fit — it handles state/session plumbing that this package deliberately leaves to you.

Gotchas and Tips

  • getName(), getImageUrl(), and getDescription() are removed in 3.0.0. Any 2.x code calling them fatals immediately. Grep before upgrading: grep -rn "getImageUrl\|->getName()\|getDescription()" app/. Replace with toArray()['username'], ['profile_picture_url'], and (for description) nothing — the field has no Basic Display equivalent.
  • The new endpoints are themselves out of date. 3.0.0 targets the Instagram Basic Display API, which Meta retired in favour of "Instagram API with Instagram Login" on the Graph host. Use the new host option if it covers your case; otherwise check all three hard-coded URLs (getBaseAuthorizationUrl, getBaseAccessTokenUrl, getResourceOwnerDetailsUrl) against current docs and override them — that remains the intended extension point. The host option typically does not cover the authorize/token hosts.
  • Default scope silently narrowed to ['user_profile']. Upgrading from 2.x can therefore break media-posting/media-reading flows with a 400/permission error that looks unrelated. Pass ['user_profile', 'user_media'] explicitly if you need media — and only if those scopes are granted in the Meta dashboard.
  • No standard refresh-token grant. getAccessToken('refresh_token', ...) will not work. Long-lived tokens come from a non-standard grant_type=ig_exchange_token exchange and are refreshed via ig_refresh_token; perform that yourself and store the result. AccessToken::getRefreshToken() will be null.
  • Scopes must be pre-approved in the Meta app dashboard. Failures surface at the token step as an IdentityProviderException, not at the redirect, and the message rarely names the missing scope.
  • redirectUri must match byte-for-byte (scheme, host, trailing slash, query). Still the #1 cause of invalid redirect_uri.
  • Exceptions are League\OAuth2\Client\Provider\Exception\IdentityProviderException from getAccessToken/getResourceOwner. Inspect $e->getResponseBody() — Graph returns {"error": {"message": ..., "type": ...}}, which the default checkResponse may not surface cleanly.
  • State handling is yours. getAuthorizationUrl() generates state and getState() returns it, but nothing validates the callback. Compare against the session value and reject mismatches.
  • Need the removed fields back? Subclass the provider and override createResourceOwner() with your own InstagramResourceOwner subclass that re-adds the keys you rely on — cleaner than normalising in ten controllers.
  • Debugging HTTP: pass a Guzzle client with logging middleware via httpClient. OAuth failures are almost always legible in the raw response body.
  • PKCE: still not opted in; Instagram's confidential-client flow doesn't require it. Public clients must override getPkceMethod().
  • Upgrade league/oauth2-client deliberately. This provider tracks v2.x APIs; v3 changes getResourceOwner internals, and 3.0.0 of this package won't have accounted for it.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle