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 Bundle Laravel Package

happyr/linkedin-bundle

Symfony bundle for LinkedIn integration that provides OAuth authentication and API client wiring, making it easier to add LinkedIn login and profile/data access to PHP applications with configurable services and less boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and register. The bundle is a thin Symfony wrapper around happyr/linkedin-api-client, so you get both packages:

composer require happyr/linkedin-bundle

Register it in app/AppKernel.php (or config/bundles.php on Symfony 3.4+):

new HappyR\LinkedInBundle\HappyRLinkedInBundle(),

The package has just cut 1.0.0, its first stable release — previously it sat on a 2018-era tag with no stability commitment. That is good news for constraint hygiene (you can now pin ^1.0 and expect semver), but the release notes are a single line with no changelog, so they tell you nothing about what changed. Run composer show happyr/linkedin-bundle and read the tag diff before assuming the Symfony constraint moved: if 1.0.0 still declares ^2.8|^3.0, it will not install cleanly on Symfony 5/6 without forking or dropping the bundle and using the client directly.

Configure. Three values only, all of which must match what is registered in your LinkedIn app:

happyr_linkedin:
    client_id:     "%linkedin_client_id%"
    client_secret: "%linkedin_client_secret%"
    redirect_url:  "%linkedin_redirect_url%"   # absolute, must match exactly

Where to look first. Before writing any code, open vendor/happyr/linkedin-bundle/Resources/config/ and confirm two things: the service id you should inject (historically happyr_linkedin.client), and whether the bundle registers a storage service. On a fresh 1.0.0, also open composer.json and the LinkedIn client constructor to see whether the defaults changed between the old tag and now. Then read the client's own README in vendor/happyr/linkedin-api-client/ — the bundle has almost no logic of its own, so the client is the real API surface (getLoginUrl(), getAccessToken(), isAuthenticated(), get(), post(), api()).

First use case: OAuth login. Two controllers — one that redirects to $linkedin->getLoginUrl($scopes, $state), one that receives ?code=...&state=..., exchanges it via getAccessToken($code), and loads the profile. That is the whole happy path; everything else is variations on it.

Implementation Patterns

Do the OAuth dance explicitly. Don't hide the redirect inside a listener. A /connect/linkedin action builds the login URL, the callback action validates state against the value you stored in the Symfony session, then exchanges the code. Explicit controllers are far easier to debug than a bundle-managed flow, and the client does not validate state for you.

Persist the token on your own entity, not in the session. The client is a stateful object: setAccessToken() writes into a storage backend, and isAuthenticated() reads from it. Treat that as per-request convenience only. Store the access token (and the LinkedIn member id) on your User row, then re-hydrate on each request:

$linkedin = $this->get('happyr_linkedin.client');
$linkedin->setAccessToken($user->getLinkedinToken());
$profile = $linkedin->get('/v2/me', ['projection' => '(id,localizedFirstName,localizedLastName)']);

Wrap it in your own service. Inject the client into a LinkedInGateway class rather than calling the container, exposing intent-named methods (fetchProfile(), fetchEmail(), sharePost()). This gives you one place to add logging, retries, and 401 handling — and one interface to fake in tests, which matters because you cannot hit LinkedIn from CI. The new 1.0.0 tag makes this seam more valuable, not less: if the stable release turns out to contain breaking changes you did not spot in the one-line notes, the gateway is the only file that needs to move.

Map to your domain immediately. LinkedIn returns its own vocabularies (localized first/last name, elements arrays on collection endpoints). Convert to your User fields at the boundary and never let raw LinkedIn arrays leak into your application layer. The API shape changes more often than your entity should.

Use api() for anything the convenience methods don't cover. The client's convenience endpoints and scope constants predate the v2 API; passing explicit paths to get()/post() is the supported escape hatch and is how you survive deprecations without forking the package. Verify this still holds on 1.0.0 — a stable release is exactly when convenience methods get renamed or removed.

Gotchas and Tips

"First stable release" is not the same as "modernised." 1.0.0 means the maintainers are willing to commit to the public API from here on; it does not, by itself, mean the v1→v2 LinkedIn migration is done or that Symfony 5/6 constraints were widened. The release notes are a single line, so treat the two questions as open until you read the diff: (a) does composer.json still cap Symfony at ^3.0, and (b) do the defaults still point at /v1/people/~? If either answer is unchanged, everything below about the v1 retirement still applies verbatim. Anything hitting /v1/people/~ or using r_basicprofile/r_fullprofile will fail — you must call /v2/me and /v2/emailAddress?q=members&projection=(elements*(handle~)) with scopes r_liteprofile, r_emailaddress, w_member_social. The client will still make the HTTP call; it just won't like the answer. Budget for this before evaluating the bundle at all.

Redirect URL mismatches are the #1 failure. The same string is used to build the authorize URL and to compute the token exchange. It must be absolute, HTTPS (LinkedIn requires it outside localhost), and byte-identical to the app registration — including trailing slash. A mismatch produces an opaque invalid_request from LinkedIn, not a helpful exception.

Sessions are a trap. The client's default storage is $_SESSION-backed. That's invisible when it works and breaks in CLI commands, tests, and any request where the session hasn't started, plus it silently shares state across users in long-running workers (RoadRunner, Swoole, Messenger consumers). Swap in a storage implementation backed by Symfony's SessionInterface, and never reuse a single client instance across two users. Re-check the storage default on 1.0.0 — if they changed it, this is the one breaking change most likely to bite silently.

Handle non-200s explicitly. The client throws on API errors rather than returning them. Wrap calls in try/catch, distinguish 401 (token expired — send the user through OAuth again) from 403 (scope not granted on the app) from 429 (rate limited). Log the raw response body; LinkedIn's error payloads are the only useful diagnostic you'll get.

Config validation is minimal. There is no compile-time check that your three settings are non-empty, so a missing env var surfaces as a malformed login URL rather than a boot error. Add an assertion in a compiler pass or a small config test if this integration is load-bearing.

Prefer the raw client over the bundle if you're on modern Symfony. Because the bundle contributes only a service definition and a config tree, on Symfony 4+ you can register HappyR\LinkedIn\LinkedIn yourself as a service with three constructor arguments and skip the bundle entirely — fewer version constraints, same functionality, and the client package is the piece that actually needs patching. This remains the safest path when you can't confirm from a one-line changelog what 1.0.0 actually stabilised.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource