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

Linkedin Laravel Package

socialiteproviders/linkedin

Community-maintained LinkedIn OAuth provider for Laravel Socialite. It adds LinkedIn sign-in and user profile retrieval to your Laravel application through a simple Composer install, client ID and secret configuration, and the standard Socialite driver API you already know.

Deep Wiki
Context7

Getting Started

This package is a community provider for Laravel Socialite that adds a linkedin driver. It is a subtree split of SocialiteProviders/Providers, so the repo you see is generated — treat the monorepo as the upstream source of truth, but composer require pulls the split package directly.

1. Install

composer require socialiteproviders/linkedin

This pulls in socialiteproviders/manager, which does the actual driver registration.

2. Register the Socialite listener

Laravel 11+ (bootstrap/app.php / AppServiceProvider::boot):

use Illuminate\Support\Facades\Event;
use SocialiteProviders\Manager\SocialiteWasCalled;

Event::listen(SocialiteWasCalled::class, function (SocialiteWasCalled $event) {
    $event->extendSocialite('linkedin', \SocialiteProviders\LinkedIn\LinkedInExtendSocialite::class);
});

Laravel ≤10 (app/Providers/EventServiceProvider.php):

protected $listen = [
    \SocialiteProviders\Manager\SocialiteWasCalled::class => [
        \SocialiteProviders\LinkedIn\LinkedInExtendSocialite::class.'@handle',
    ],
];

3. Configure credentials in config/services.php:

'linkedin' => [
    'client_id'     => env('LINKEDIN_CLIENT_ID'),
    'client_secret' => env('LINKEDIN_CLIENT_SECRET'),
    'redirect'      => env('LINKEDIN_REDIRECT_URI'),
],

4. First use case — a "Sign in with LinkedIn" button:

Route::get('/auth/linkedin/redirect', fn () => Socialite::driver('linkedin')->redirect());
Route::get('/auth/linkedin/callback', function () {
    $linkedinUser = Socialite::driver('linkedin')->user();
    // $linkedinUser->getId(), ->getName(), ->getEmail(), ->getAvatar()
});

Where to look first in the installed vendor directory:

  • src/LinkedInExtendSocialite.php — the one-liner that registers the driver.
  • src/LinkedInProvider.php — scopes, endpoints, scope defaults, and the mapUserToObject implementation. Read this before debugging.
  • composer.json — confirms the Socialite version constraint (usually ^5.x) and PHP floor (^8.x).

Implementation Patterns

Controller/service class split. Keep OAuth redirect plumbing out of controllers that also do business logic. A small LinkedInAuthService wrapping Socialite::driver('linkedin') makes it far easier to mock and reuse across web + API entry points.

Standard login flow with account linking.

class LinkedInCallbackController
{
    public function __invoke(Request $request, LinkedInAuthService $linkedIn)
    {
        $remote = $linkedIn->user(); // wraps Socialite::driver('linkedin')->user()

        $user = User::updateOrCreate(
            ['linkedin_id' => $remote->getId()],
            [
                'name'  => $remote->getName() ?? 'LinkedIn User',
                'email' => $remote->getEmail(), // may be null — see gotchas
            ]
        );

        Auth::login($user, remember: true);
        return redirect()->intended('/dashboard');
    }
}

Guard against takeover: only match on linkedin_id, and reconcile by email explicitly with user confirmation — never User::firstOrCreate(['email' => $remote->getEmail()]) blindly.

Stateless / API + SPA usage. Socialite stores state in the session. For token-based or cross-domain flows, use stateless mode and validate state yourself:

Socialite::driver('linkedin')->stateless()->redirect();

// callback
$user = Socialite::driver('linkedin')->stateless()->user();

Custom scopes. Pass scopes per request rather than editing the provider:

Socialite::driver('linkedin')
    ->scopes(['openid', 'profile', 'email', 'w_member_social'])
    ->redirect();

Scopes must be enabled on the LinkedIn app (Products tab) or LinkedIn rejects the authorize request before it ever reaches your callback.

Testing. Socialite has no built-in fake for third-party providers, so wrap the driver and bind an interface in the container:

$this->mock(LinkedInAuthService::class, function ($mock) {
    $mock->shouldReceive('user')->andReturn(
        (new \Laravel\Socialite\Two\User)->map([
            'id' => 'abc123', 'name' => 'Test', 'email' => '[email protected]',
        ])
    );
});

Refresh / re-auth. LinkedIn tokens are short-lived; for API calls use Socialite::driver('linkedin')->userFromToken($token) where supported, or store refresh_token and hit the token endpoint directly. Don't assume the token from user() persists.

Integration tip — pair with the OIDC driver. Core Socialite ships linkedin-openid. If you only need login (no legacy v2 API fields), prefer linkedin-openid and drop this package; use socialiteproviders/linkedin when you need the SocialiteProviders manager integration, custom scopes, or a unified driver registry across many providers.

Event-driven registration scales cleanly. In apps with many SocialiteProviders packages, register a single listener that loops a config array of provider => handler classes rather than a pile of individual listeners.

Gotchas and Tips

Redirect URI is exact-match, HTTPS-only. LinkedIn compares the redirect_uri character-for-character. Trailing slash, http vs https, www vs apex, and port mismatches all cause redirect_uri does not match. Local dev typically needs https://127.0.0.1:8000/... or a tunnel (ngrok/Valet share) — plain http://localhost often fails.

"Driver [linkedin] is not supported." Almost always the SocialiteWasCalled listener is missing, wrong, or not booted (config/event cache). Run php artisan event:cache after adding it, and verify with php artisan event:list | grep Socialite.

Email can be null. Even with the email scope, LinkedIn can omit it (users can hide email). Always handle null in updateOrCreate and in your "verified email" assumptions — don't mark it verified just because LinkedIn returned it.

Scopes are the #1 source of silent failures. LinkedIn's current product is Sign In with LinkedIn using OpenID Connect (openid profile email). Legacy r_liteprofile / r_emailaddress scopes are deprecated and error for apps created after the cutoff. Check LinkedInProvider::getScopes() in src/ and override per driver:

Socialite::driver('linkedin')->scopes(['openid', 'profile', 'email'])->redirect();

Avatar URLs expire. getAvatar() returns a signed CDN URL with a lifespan; persist it for display or download it to your own storage during signup, don't cache the URL forever.

InvalidStateException / session issues. Symptoms: state mismatch on callback. Causes: stateless flow used but you called the stateful redirect(), cross-subdomain cookie scope, SESSION_DRIVER=array, or the user opened multiple login tabs. Fix by matching stateful/stateless consistently and setting SESSION_DOMAIN correctly.

API versioning header. LinkedIn's REST API requires a Linkedin-Version header (e.g. 202411) on non-OAuth calls. If you extend the provider to call LinkedIn endpoints, set it — an outdated version yields 426 Upgrade Required.

Extending the provider. To customize fields or endpoints, subclass:

class MyLinkedInProvider extends \SocialiteProviders\LinkedIn\LinkedInProvider
{
    protected function mapUserToObject(array $user): \Laravel\Socialite\Two\User { /* ... */ }
    public function getAuthUrl($state): string { /* ... */ }
}

Then register MyLinkedInProvider in the SocialiteWasCalled listener instead of the package's class. Prefer this over editing vendor files — subtree splits overwrite on composer update.

Config caching bites. php artisan config:clear after changing services.php, and remember cached config ignores .env mutations in production-like setups. A "wrong client_id" bug is frequently a stale config cache.

Subtree split lag. The standalone README can trail the monorepo. If a scope or endpoint looks wrong, check SocialiteProviders/Providers on GitHub and pin the version in composer.json when relying on recent changes (last release 2024-11-27 — verify it supports the current LinkedIn OIDC behavior before assuming).

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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo