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

Saml2 Laravel Package

socialiteproviders/saml2

SAML2 provider for Laravel Socialite that lets Laravel apps authenticate users through SAML 2.0 identity providers. Add enterprise SSO to your existing Socialite login flow with a familiar driver interface and minimal configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is a thin Socialite driver over a PHP SAML toolkit. Its value is that enterprise SSO fits the same redirect() / user() shape you already use for GitHub or Google, rather than introducing a second authentication framework. Use it when the IdP speaks SAML2 (Okta, Azure AD/Entra, ADFS, Ping, Shibboleth) and you want Socialite as the application-facing abstraction.

Minimal setup:

composer require socialiteproviders/saml2

Register the driver. On older Laravel skeletons, add the listener to EventServiceProvider; on Laravel 11+, register it in AppServiceProvider or a dedicated provider:

use Illuminate\Support\Facades\Event;
use SocialiteProviders\Manager\SocialiteWasCalled;
use SocialiteProviders\Saml2\Saml2ExtendSocialite;

Event::listen(SocialiteWasCalled::class, Saml2ExtendSocialite::class.'@handle');

Configure the driver in config/services.php. Socialite still expects client_id, client_secret, and redirect; in SAML terms these map to the SP entity ID, SP key material (often unused unless signing/decryption is enabled), and the Assertion Consumer Service URL. The IdP block — SSO URL, entity ID, signing certificate — is driver-specific, so verify the exact keys against the installed README and provider source.

'saml2' => [
    'client_id' => env('SAML2_SP_ENTITY_ID'),
    'client_secret' => env('SAML2_SP_PRIVATE_KEY', ''),
    'redirect' => env('SAML2_ACS_URL', env('APP_URL').'/auth/saml2/callback'),
    // IdP metadata / certificate keys per driver version
],

Add the two routes. The redirect is a normal GET; the callback must accept POST, because SAML HTTP-POST binding posts the assertion to the ACS:

Route::get('/auth/saml2/redirect', fn () => Socialite::driver('saml2')->redirect());
Route::post('/auth/saml2/callback', [SamlController::class, 'callback']);

Where to look first: the package README for the exact config shape, the provider class for getAuthUrl() and mapUserToObject(), and your IdP's SAML metadata. Your first use case should be a single IdP and a single test tenant — do not start with multi-tenant routing or encrypted assertions.

Implementation Patterns

Standard SP-initiated login. Let Socialite generate the AuthnRequest, then resolve the user in the callback:

public function callback(Request $request)
{
    try {
        $samlUser = Socialite::driver('saml2')->user();
    } catch (\Throwable $e) {
        report($e);
        return redirect('/login')->withErrors('SSO failed. Try again.');
    }

    $user = User::updateOrCreate(
        ['email' => $samlUser->getEmail()],
        ['name' => $samlUser->getName()]
    );

    Auth::login($user, remember: true);

    return redirect()->intended('/dashboard');
}

Claim mapping. Socialite's AbstractUser exposes id, name, email, nickname, and the raw payload via $samlUser->user. Most teams map the SAML NameID or immutable ID to a local sso_id, then use email only as a fallback. Avoid keying users by email alone if the IdP allows reassignment. For roles/groups, read the raw assertion attributes and map them explicitly:

$groups = (array) ($samlUser->user['groups'] ?? []);
$user->syncRoles($this->mapGroups($groups));

Preserving the intended URL. SAML's RelayState is the natural place for this, but Socialite's flow and the driver's handling of RelayState vary. A reliable pattern is to store the intended URL in the session before redirecting, then consume it after login. Do not assume the IdP returns arbitrary query parameters on the ACS URL.

Multi-tenant or multiple IdPs. Treat each IdP as a separate configuration and resolve the driver per tenant. Be careful: Socialite caches resolved drivers within the request/container, and config is read when the driver is constructed. In long-running workers, reset or rebuild the driver per request. A common design is one route per tenant (/auth/{tenant}/saml2/...) that swaps services.saml2 config before calling Socialite.

Testing. Unit-test the callback with a mocked Socialite driver (Socialite::shouldReceive('driver')). For integration, run a local IdP (SimpleSAMLphp) or a hosted test IdP, and keep a known assertion fixture. Log the raw SAML response only in local/staging — it contains PII and is security-sensitive.

Integration with existing auth. Keep SAML as an additional guard or login route rather than replacing password auth immediately. A staged rollout — SSO for one team, local login retained for break-glass admins — is much easier to operate.

Gotchas and Tips

  • The callback is POST, not GET. Socialite examples are GET-centric. A GET-only callback route will silently 405 at the IdP's ACS POST. Exclude the ACS route from CSRF (bootstrap/app.php / VerifyCsrfToken) or handle the token correctly.
  • ACS URL and entity ID must match exactly. Scheme, host, port, trailing slash, and case matter. A mismatch produces generic "invalid request" or "response not valid" errors. Confirm what the IdP has stored against what the SP sends in its AuthnRequest.
  • Certificate formatting is the most common failure. IdPs hand out base64 DER certificates; SAML libraries usually expect PEM. Watch for literal \n in .env values, missing -----BEGIN CERTIFICATE----- wrappers, or expired IdP signing certs. Validate with openssl x509 -in cert.pem -text -noout.
  • Config caching bites. After changing SAML config, run php artisan config:clear. A stale cached entity ID or ACS URL is indistinguishable from an IdP misconfiguration.
  • IdP metadata should be cached, not fetched at boot. If the driver fetches metadata from a URL on every request, add caching or pin the XML. Metadata endpoints are an external dependency on your login path.
  • Session state matters. SP-initiated flows rely on session state for request correlation. Multiple tabs, load-balanced nodes without shared sessions, or SameSite cookie issues cause intermittent "invalid response" errors. Use a shared session store in production.
  • Clock skew and assertion lifetime. IdP and SP clocks must be close. Small NotBefore/NotOnOrAfter windows plus skew cause sporadic failures that are hard to reproduce.
  • client_secret is often unused. Don't assume it is an OAuth client secret. It may represent an SP private key only when request signing or assertion decryption is enabled.
  • Encrypted assertions require an SP key pair. If the IdP encrypts assertions, plain metadata-only configuration will fail. Generate an SP key, publish the certificate to the IdP, and configure the private key.
  • Attribute names are IdP-specific. Azure AD emits claim URIs; Okta and ADFS often emit short names. Never hard-code a single shape — normalize in one mapping function and fail loudly when required claims are missing.
  • Error handling is not OAuth-shaped. SAML errors may arrive as a POSTed SAMLResponse, a redirect with an error parameter, or a library exception. Catch broadly at the controller boundary, log a correlation ID, and show a generic message to the user.
  • IdP-initiated flows and single logout are usually out of scope. Socialite's model is SP-initiated. If the business requires IdP-initiated login or SAML single logout, verify support early; this driver likely does not provide full SLO.
  • Package maturity is a real risk. At 17 stars, this is a thin, low-adoption wrapper. Pin the version, understand the underlying SAML library it depends on, and be prepared to fork the mapUserToObject() / config layer. If requirements grow beyond basic SSO, compare against a dedicated Laravel SAML package rather than stretching this driver.
  • Local development needs a public HTTPS ACS URL. Most IdPs will not redirect to http://localhost. Use a tunnel and register that exact ACS URL in the IdP test tenant.
  • Extension points. Subclass the provider to override attribute mapping, publish/override config, and keep IdP-specific quirks in your application rather than patching vendor code. Use Socialite's with() sparingly — SAML does not have OAuth scopes, and unknown parameters may be ignored.
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
shitoudev/permissionmanager