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

Streamelements Laravel Package

socialiteproviders/streamelements

StreamElements OAuth provider for Laravel Socialite, letting apps add StreamElements login and fetch authenticated user profiles with a standard Socialite driver. Simple setup for Laravel authentication flows.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal path from zero to a working "Sign in with StreamElements" flow on a package version in the 5.1.x line:

  1. Install the provider and its Socialite dependency:
    composer require socialiteproviders/streamelements
    
  2. Register the SocialiteProviders hook. The package follows the shared SocialiteProviders\Manager pattern: the driver is not registered by the provider itself, but by the manager's SocialiteWasCalled event.
    • Laravel ≤ 10: in app/Providers/EventServiceProvider.php add to $listen:
      \SocialiteProviders\Manager\SocialiteWasCalled::class => [
          \SocialiteProviders\StreamElements\StreamElementsExtendSocialite::class.'@handle',
      ],
      
    • Laravel 11/12 (no EventServiceProvider): register the same listener in AppServiceProvider::boot() or bootstrap/app.php:
      Event::listen(
          \SocialiteProviders\Manager\SocialiteWasCalled::class,
          \SocialiteProviders\StreamElements\StreamElementsExtendSocialite::class.'@handle'
      );
      
    • If you already use another SocialiteProviders package, the listener for SocialiteWasCalled is already registered; just add the StreamElementsExtendSocialite entry alongside it.
  3. Add credentials to config/services.php, reading from .env:
    'streamelements' => [
        'client_id'     => env('STREAMELEMENTS_CLIENT_ID'),
        'client_secret' => env('STREAMELEMENTS_CLIENT_SECRET'),
        'redirect'      => env('STREAMELEMENTS_REDIRECT_URI'),
    ],
    
  4. Create the OAuth app in the StreamElements dashboard, and set the redirect URI to exactly the value in STREAMELEMENTS_REDIRECT_URI. Nothing in this package can work around a mismatch here.
  5. First use case — the canonical login route pair:
    Route::get('/auth/streamelements', fn () => Socialite::driver('streamelements')->redirect());
    
    Route::get('/auth/streamelements/callback', function () {
        $user = Socialite::driver('streamelements')->user();
    
        // $user->getId()      -> stable StreamElements account id
        // $user->getNickname() -> display/username
        // $user->getEmail()    -> may be null depending on scopes
        return $user->getRaw();
    });
    
    Dump getRaw() once on your first successful callback before writing any persistence logic — it is the fastest way to confirm which fields your account actually returns.

Where to look first when something is off: the SocialiteProviders\StreamElements provider class (endpoints, scope defaults, and the user-mapping method getUserByToken/mapUserToObject), then config/services.php, then the registered event listener.

Implementation Patterns

Standard web-login controller. Keep a thin controller and push persistence into an action class so you can reuse it from an API context:

public function callback(): RedirectResponse
{
    $seUser = Socialite::driver('streamelements')->user();

    $account = StreamerAccount::updateOrCreate(
        ['streamelements_id' => $seUser->getId()],
        [
            'username'     => $seUser->getNickname(),
            'email'        => $seUser->getEmail(),
            'access_token' => encrypt($seUser->token),
            'refresh_token'=> $seUser->refreshToken ? encrypt($seUser->refreshToken) : null,
            'expires_at'   => $seUser->expiresIn ? now()->addSeconds($seUser->expiresIn) : null,
        ],
    );

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

Stateless mode for API/first-party flows. If you drive the callback from an API, a mobile app, or a popup window where the session cookie may not round-trip, use ->stateless(). Otherwise Socialite's state check will throw InvalidStateException even though StreamElements authenticated the user correctly.

Scope handling. StreamElements uses granular scopes (channel:read, chat:write, tips:read, points:write, overlays:read, bot:write, activities:read, and similar), and they are per-capability rather than per-resource. Two patterns:

  • Login identity only: request nothing beyond the defaults and treat the token as an identity proof, not an API token.
  • Acting on the account later: request the scopes you actually need at login time and store the token — you cannot silently upgrade scopes after the fact; the user has to re-consent.
    Socialite::driver('streamelements')
        ->setScopes(['channel:read', 'tips:read', 'points:read'])
        ->redirect();
    
    Confirm the exact scope strings in the StreamElements developer dashboard at the time you build — unknown scopes fail with invalid_scope, not a warning.

Decouple "who they are" from "what we can do." Store the StreamElements id as the primary external key, keep the username as a mutable display field, and keep tokens in a separate table/column set with an expires_at. A StreamElements id is the only field stable enough to key on; usernames are renamable.

Refresh as a job, not inline. Because the Socialite user object gives you refreshToken and expiresIn, wrap the refresh call in a queued job that runs ahead of expiry:

Http::asForm()->post('https://api.streamelements.com/oauth2/token', [
    'grant_type'    => 'refresh_token',
    'refresh_token' => decrypt($account->refresh_token),
    'client_id'     => config('services.streamelements.client_id'),
    'client_secret' => config('services.streamelements.client_secret'),
]);

Testing. There is no Socialite::fake() for arbitrary drivers; mock the driver facade instead:

Socialite::shouldReceive('driver->user')->andReturn(
    (new \Laravel\Socialite\Two\User)->map([
        'id' => 'abc-123', 'nickname' => 'streamer', 'email' => null,
    ])
);

Extension point. If StreamElements changes its /me payload or you need extra fields (partner status, account type), the cleanest approach is to subclass the provided provider, override the user-mapping method, and register your class as the driver via Socialite::extend() rather than editing vendor code.

Gotchas and Tips

  • Driver [streamelements] is not supported — almost always the SocialiteWasCalled listener is missing or the handle method isn't registered under the manager package. This is the single most common setup failure. Check it before debugging credentials.
  • Redirect URI mismatch is the second most common failure and the error surfaces from StreamElements, not Laravel. http vs https, a trailing slash, www vs apex, or a port difference will all break it. Copy-paste, don't retype.
  • Config caching. After editing config/services.php in a deployed environment, php artisan config:cache must be re-run (or config:clear locally). Stale config reads as "credentials are wrong" when they aren't.
  • getEmail() can be null. StreamElements does not guarantee an email in the profile payload for every account type; make the column nullable and never rely on email for identity or account linking.
  • user() throws, it doesn't return null. Wrap the callback in a try/catch for Laravel\Socialite\Two\InvalidStateException and the generic \Throwable from the token exchange, and redirect to a friendly error page rather than a 500. The exception message contains the OAuth error code (invalid_grant, invalid_scope) — log it verbatim; it's usually sufficient to diagnose without a debugger.
  • Tokens are short-lived. Do not assume the login token is still usable days later just because you stored it. Gate any StreamElements API call behind an expires_at check and a refresh.
  • stateless() in the wrong place. Adding it to fix an InvalidStateException in a normal server-rendered login flow removes CSRF protection from the OAuth round-trip. Only use it where you genuinely have no session.
  • Debugging payload shape. $user->getRaw() is your friend; there's no need to enable HTTP logging to see what the provider parsed. If you need the actual HTTP exchange, drop a temporary Log::debug in your subclassed provider's request method rather than at the HTTP client level.
  • 5.1.0 vs 5.0.0. The release notes for 5.1.0 are a bare changelog link with no entries; treat it as a minor, non-breaking bump. Practical advice: constrain to ^5.1 in composer.json, and when you next run composer update, watch the resolved laravel/socialite and socialiteproviders/manager versions — breakage in these packages almost always comes from a Socialite/Manager major bump rather than from the provider itself.
  • No migration guide exists between the 5.0 and 5.1 tags. If something regresses on upgrade, diff the provider class between tags rather than searching for release documentation; the change surface is small enough that this is fast.
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.
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
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource