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

Laravel Openid Connect Laravel Package

jeremy379/laravel-openid-connect

A Laravel package for adding OpenID Connect authentication to your app. Let users sign in through any compliant OIDC provider with a simple configuration-driven flow covering authorization, token exchange, and user info retrieval.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and wire up

composer require jeremy379/laravel-openid-connect
  1. Add an OIDC entry to config/services.php — this is the first place to look, it's where all package configuration lives:
'oidc' => [
    'client_id'     => env('OIDC_CLIENT_ID'),
    'client_secret' => env('OIDC_CLIENT_SECRET'),
    'redirect'      => env('OIDC_REDIRECT_URI'),   // must match the IdP registration exactly
    'base_url'      => env('OIDC_BASE_URL'),       // e.g. https://idp.example.com
    'scopes'        => ['openid', 'profile', 'email'],
],
  1. The package auto-registers a Socialite driver, so there is no publish step for most setups. The driver name is the key you chose above (oidc).
  2. Create the two routes — one to redirect out, one to handle the callback:
Route::get('/auth/redirect', fn () => Socialite::driver('oidc')->redirect());
Route::get('/auth/callback', function () {
    $user = Socialite::driver('oidc')->user();
    // $user->id (the `sub` claim), $user->name, $user->email, $user->token
});

First use case: "log in with our corporate IdP" — one OIDC provider, session-based login, sub claim mapped to a local users row. Everything else (discovery document fetch, JWKS retrieval, id_token signature validation, token exchange) is handled for you.

Version note: 3.3.0 is a maintenance release — PHP 8.5 CI coverage plus removal of the deprecated ReflectionMethod::setAccessible() call. No API changes, no config changes. It's a safe drop-in from 3.2.x and the first version to be clean on PHP 8.5.

Implementation Patterns

Persisting the identity. The sub claim is the only stable identifier — store it in its own indexed column (oidc_sub) and use it for lookup, then treat email/name as refreshable attributes. Emails get reassigned; sub values don't.

$user = User::updateOrCreate(
    ['oidc_sub' => $oidcUser->getId()],
    ['name' => $oidcUser->getName(), 'email' => $oidcUser->getEmail()]
]);
Auth::login($user);

Keeping the raw tokens. $user->token gives you the access token and the raw response is on $user->user / the access token response. Persist the refresh_token if you need to call downstream APIs after login, and store expires_in alongside it rather than assuming a lifetime.

RP-initiated logout. Pair the login flow with the package's logout support so the IdP session is actually terminated rather than just your Laravel session:

return redirect(Socialite::driver('oidc')->logout($idToken, route('home')));

Keep the id_token from login in the session for the id_token_hint — without it, many IdPs either refuse the logout or prompt the user.

Multiple providers / tenants. Register several keys in config/services.php (oidc, oidc-partner, …) and resolve the driver name from the request (subdomain, route prefix, or an auth_providers table). This is cheaper than instantiating the provider manually and keeps discovery/JWKS caching per-provider.

Testing. Fake the discovery and token endpoints with Http::fake() in feature tests rather than mocking the provider — that exercises the real token validation path. For unit-level controller tests, Socialite::shouldReceive('driver->user') and return a stub with getId()/getEmail(). Include one test with a genuinely expired/forged id_token so you notice if signature verification ever silently degrades.

Route placement. Put the callback behind the web middleware group — Socialite relies on the session for state and nonce correlation. API-only apps should either add a lightweight session or handle the flow in a dedicated stateful route group.

Gotchas and Tips

  • redirect must be byte-identical to what's registered at the IdP — scheme, host, trailing slash, port. This is the single most common "it works locally, fails in staging" cause.
  • state/nonce mismatches throw Laravel\Socialite\Two\InvalidStateException. In practice this means the session was lost between redirect and callback: wrong middleware group, SESSION_DRIVER=array, a load balancer without sticky sessions, or a user who sat on the login page until the session expired.
  • Discovery and JWKS are cached. After an IdP rotates keys or you change base_url, clear the cache or you'll chase phantom signature failures. Conversely, don't disable caching in production — you'll add a round trip to every request in the flow.
  • Scopes must include openid. Without it you get a plain OAuth2 response, no id_token, and user() returns a half-populated object. profile and email are what actually populate name/email.
  • Claims may live only in the id_token. If user() returns empty name/email, the provider isn't exposing a userinfo endpoint or the claims you asked for aren't in the granted scopes — check the raw response before assuming a package bug.
  • Clock skew produces iat/exp validation failures on otherwise-valid tokens. If you control the IdP, keep hosts on NTP; if not, be aware there's limited tolerance and near-zero drift budgets on some providers.
  • Debug by logging the raw token response, not by stepping through the provider. Nearly every failure in this flow is a configuration mismatch visible in the request/response pair (wrong client_id, missing client_secret for confidential clients, mismatched redirect, unregistered scope).
  • Extension point: the provider is a Socialite driver, so Socialite::extend('oidc', …) and the standard Socialite custom-provider patterns still apply if you need to override scope handling or claim mapping rather than forking the package.
  • PHP 8.5 readiness: 3.3.0 removes the ReflectionMethod::setAccessible() call that emitted deprecation notices, so if you're testing against 8.5 you can drop any error_reporting suppression you added around the package.
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.
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox