jeffersongoncalves/laravel-oidc

OpenID Connect for Laravel via a custom Socialite driver. Multi-tenant ready.

Maintainers

Package info

github.com/jeffersongoncalves/laravel-oidc

pkg:composer/jeffersongoncalves/laravel-oidc

Fund package maintenance!

jeffersongoncalves

Statistics

Installs: 27

Dependents: 1

Suggesters: 0

Stars: 1

Open Issues: 0

v1.0.0 2026-04-26 00:02 UTC

This package is auto-updated.

Last update: 2026-04-26 00:10:02 UTC


README

Laravel OIDC

Laravel OIDC

Latest Version on Packagist Total Downloads GitHub Tests Action Status GitHub Code Style Action Status License

Laravel OIDC adds first-class OpenID Connect support to Laravel by registering a custom Laravel Socialite driver named oidc. Unlike vanilla Socialite — which covers OAuth 2.0 but stops at the userinfo step — this package implements the OIDC pieces Socialite leaves out: discovery (/.well-known/openid-configuration), JWKS-based id_token validation, nonce-based replay protection, and PKCE.

It is designed for multi-tenant SaaS: configuration is supplied at runtime, so each tenant can connect its own Azure AD, Okta, Auth0, Google Workspace, Keycloak, or any other spec-compliant OpenID Provider.

Compatibility

Package Laravel PHP
1.x 11.x, 12.x, 13.x 8.2, 8.3, 8.4

Why?

Laravel Socialite ships drivers for fixed providers (GitHub, Google, etc.) and a small set of OAuth 2.0 helpers. It does not:

  • Read the IdP's .well-known/openid-configuration discovery document.
  • Validate the id_token JWT against the IdP's JWKS.
  • Send and verify a nonce to mitigate replay attacks.
  • Make per-request configuration easy in multi-tenant scenarios.

This package adds those pieces while staying inside the Socialite mental model: you still call Socialite::driver('oidc')->redirect() and ->user().

Installation

composer require jeffersongoncalves/laravel-oidc

Optionally publish the config file:

php artisan vendor:publish --tag="oidc-config"

Configuration

The package works out of the box. For single-tenant apps, set the default IdP in .env:

OIDC_ISSUER_URL=https://login.microsoftonline.com/{tenant-id}/v2.0
OIDC_CLIENT_ID=your-app-client-id
OIDC_CLIENT_SECRET=your-app-secret
OIDC_REDIRECT_URI=https://your-app.test/sso/callback

For multi-tenant apps, leave the default block empty and supply an OidcConfig at runtime (see below).

Usage

Single-tenant (config from .env)

use Laravel\Socialite\Facades\Socialite;

Route::get('/sso/redirect', fn () => Socialite::driver('oidc')->redirect());

Route::get('/sso/callback', function () {
    $user = Socialite::driver('oidc')->user();

    // $user->id            // sub claim
    // $user->email
    // $user->name
    // $user->token         // access_token
    // $user->idToken       // raw id_token JWT
    // $user->idTokenClaims // decoded + validated claims
});

Multi-tenant (runtime config)

use Laravel\Socialite\Facades\Socialite;
use JeffersonGoncalves\LaravelOidc\Data\OidcConfig;

$config = new OidcConfig(
    issuerUrl: $tenant->issuer_url,
    clientId: $tenant->client_id,
    clientSecret: $tenant->client_secret,
    redirectUri: route('sso.callback'),
    scopes: ['openid', 'email', 'profile'],
);

return Socialite::driver('oidc')
    ->setConfig($config)
    ->redirect();

On callback:

$oidcUser = Socialite::driver('oidc')
    ->setConfig($config)
    ->user();

HasOidcConfig trait for tenant models

If you store IdP configuration on a model (a typical multi-tenant pattern), drop in the trait. It expects columns issuer_url, client_id, client_secret (cast to encrypted), redirect_uri, and an optional scopes JSON column.

use JeffersonGoncalves\LaravelOidc\Concerns\HasOidcConfig;

class SsoConnection extends Model
{
    use HasOidcConfig;
}

Socialite::driver('oidc')
    ->setConfig($ssoConnection->toOidcConfig())
    ->redirect();

Discovery without Socialite

use JeffersonGoncalves\LaravelOidc\Facades\Oidc;

$discovery = Oidc::discover('https://login.microsoftonline.com/{tenant-id}/v2.0');

$discovery->authorizationEndpoint;
$discovery->tokenEndpoint;
$discovery->userinfoEndpoint;
$discovery->jwksUri;
$discovery->issuer;

Supported Identity Providers

Any IdP that publishes a .well-known/openid-configuration discovery document and signs id_tokens with one of the allowed algorithms (RS256, RS384, RS512, ES256, ES384) will work. Examples:

IdP Issuer URL example
Azure AD / Entra ID https://login.microsoftonline.com/{tenant-id}/v2.0
Google Workspace https://accounts.google.com
Okta https://{your-org}.okta.com
Auth0 https://{your-tenant}.auth0.com/
Keycloak https://{host}/realms/{realm}
Ping Identity https://{environment}.pingone.com/{environment-id}/as

Security

  • id_token validation. Every id_token is decoded against the IdP's JWKS using firebase/php-jwt. The iss, aud, exp, and iat claims are checked, with a configurable clock-skew window.
  • Algorithm allow-list. Only the algorithms in oidc.jwt.allowed_algorithms are accepted. Symmetric algorithms (HS256 & friends) are intentionally absent — accepting them with a JWKS would enable trivial key-confusion attacks.
  • Replay protection. A random nonce is generated, stored in the session, and verified against the nonce claim in the returned id_token.
  • PKCE. Enabled by default with S256. Disable per request with new OidcConfig(..., usePkce: false).
  • Caching. The discovery document is cached for 1 hour and the JWKS for 6 hours by default; both TTLs are configurable. Use Oidc::clearCache($issuer) to invalidate after a key rotation.

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Pull requests are welcome. Please make sure tests, PHPStan and Pint all pass before opening a PR:

composer test
composer analyse
composer format

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.