socialiteproviders/streamlabs
A Laravel Socialite provider that adds Streamlabs OAuth login to your app. Install via Composer, wire up the Streamlabs listener with Socialite Providers, and authenticate users through the familiar Socialite API.
Streamlabs is a SocialiteProviders driver, so it plugs into the standard Laravel Socialite flow rather than shipping its own API client. Minimal setup:
composer require socialiteproviders/streamlabs (this pulls in socialiteproviders/manager).https://yourapp.test/auth/streamlabs/callback).config/services.php:
'streamlabs' => [
'client_id' => env('STREAMLABS_CLIENT_ID'),
'client_secret' => env('STREAMLABS_CLIENT_SECRET'),
'redirect' => env('STREAMLABS_REDIRECT_URI'),
],
EventServiceProvider::$listen →
SocialiteProviders\Manager\SocialiteWasCalled::class => [\SocialiteProviders\Streamlabs\StreamlabsExtendSocialite::class.'@handle'].
Laravel 11+: Event::listen(SocialiteWasCalled::class, [StreamlabsExtendSocialite::class, 'handle']); in AppServiceProvider::boot().Socialite::driver('streamlabs')->redirect(), one that receives the callback and calls ->user().Where to look first: the package is tiny — StreamlabsExtendSocialite, the Provider class (scope definitions, auth/token URLs, mapUserToObject()), and the README. Because 4.2.0 moved the driver to the Streamlabs v2 API, the first thing worth reading on this version is the Provider class itself: it tells you which endpoints and default scopes you are actually getting, which is more reliable than the release note.
First use case: "Log in with Streamlabs" on an account-linking page so a streamer can authorize your app to read their donation/alert data. Typical first milestone is: redirect out, come back, persist id, name, email, and the access/refresh token on your users table, then re-use the token for your own calls to the Streamlabs v2 endpoints.
Stateless vs. stateful callback. Don't copy Socialite::driver('streamlabs')->stateless()->user() blindly from tutorials. Streamlabs supports the state parameter; keep state enabled unless you have a concrete reason (e.g. mobile/native handoff) and are handling CSRF yourself.
Token storage and refresh. Streamlabs access tokens are short-lived and the token response includes expires_in and refresh_token. Persist refresh_token, an expires_at computed at exchange time, and refresh proactively before calling Streamlabs APIs. Do this in a small StreamlabsAccount model with a refreshIfExpired() method rather than inline in controllers — you will need it from jobs and queued listeners too.
Separate "login" from "connect". Two patterns share one driver:
streamlabs_id, then attach the token.?intent=connect and you update their existing row.Store the raw user() payload (json column) alongside your normalized columns. It costs nothing and is the fastest way to answer "what did Streamlabs actually return?" when you migrate across API versions.
Scopes are the real integration surface. Pass them explicitly when you need more than the driver default:
Socialite::driver('streamlabs')
->scopes(['donations.read', 'alerts.create'])
->with(['state' => $state])
->redirect();
Streamlabs scopes are granular; requesting a superset at first login causes consent friction and (depending on app review) rejected authorizations. Request the minimum at login and re-authorize for elevated scopes on the feature page that needs them.
Where to call the API. Wrap Streamlabs HTTP calls in a dedicated service (app/Services/Streamlabs/Client.php) built on Http::withToken(...)->baseUrl('https://streamlabs.com/api/v2.0'). Do not reach through Socialite for data endpoints — Socialite gives you identity plus a token, not an API client. Keeping the base URL in one place is what makes the v1→v2 shift a one-file change.
Integration tips:
route() so the redirect URI in config/services.php and the one sent to Streamlabs can never drift.error, error_description) on the callback before throwing; Streamlabs returns meaningful reasons (denied consent, invalid scope) that are otherwise swallowed by InvalidStateException / ClientException.4.2.0 is an API-version change, not a cosmetic bump. The release note is just "Use v2 api.", meaning the authorization/token/user endpoints moved to Streamlabs v2. Practical consequences:
$user->user['streamlabs'] or other nested/raw keys, compare against what v2 returns before deploying. Normalize through $user->getId(), $user->getName(), $user->getEmail(), $user->getAvatar() where possible so shape changes don't leak into your code.Pinned versions matter. If you constrain socialiteproviders/streamlabs to ^4.1, composer update won't move you and you'll silently stay on the old API. If you use this package at all, allow ^4.2 and re-test the connect flow.
"Driver [streamlabs] is not supported." Almost always the SocialiteWasCalled listener is missing or not registered — and it's a common casualty of the Laravel 10→11 upgrade, since EventServiceProvider::$listen no longer auto-exists. Also confirm the config key is services.streamlabs (lowercase) and that you cleared config cache.
Redirect URI mismatch is the #1 production failure. Streamlabs compares the URI exactly, including scheme, trailing slash, port, and www. http locally vs https in production, or a Herd/Valet domain change, will fail the token exchange with a generic error. Verify what you actually send with php artisan tinker rather than reading .env.
State/CSRF errors after login. Usually a session problem, not a Streamlabs problem: callback domain differing from the initiating domain, SESSION_DOMAIN misconfigured, session driver set to array, or the user idling past session lifetime. Check that first before blaming the driver.
Email can be null. Streamlabs may not return an email, or may return one unrelated to the user's login email. Do not use it as a unique key. Key on streamlabs_id, and if you create users from OAuth, decide explicitly whether email is required (and what to do when it's absent) — otherwise you'll get a NOT NULL violation for a subset of streamers.
Extension points are limited, by design. There's no config file to publish. If you need custom endpoints, headers, or extra token handling, extend SocialiteProviders\Streamlabs\Provider and register your subclass through Socialite::extend() — but note you then own upstream changes, including future API bumps. For anything short of an endpoint change, prefer your own HTTP client over subclassing.
Testing. The driver is hard to fake end-to-end. Standard approach: in feature tests, Socialite::shouldReceive('driver->user') with a mocked Laravel\Socialite\Two\User, and separately test your Streamlabs client against Http::fake(). That keeps the OAuth seam and the API seam independently testable.
Debugging checklist for a failing connect: config cache cleared → listener registered → redirect URI byte-identical to the dashboard → state/session sane → scope list valid → token exchange response logged. That order catches nearly every reported issue with this driver.
How can I help you explore Laravel packages today?