PHPackages                             beartropy/saml2 - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. beartropy/saml2

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

beartropy/saml2
===============

Multi-IDP SAML2 SP integration for Laravel using onelogin/php-saml

0.3.8(1mo ago)1317MITPHPPHP ^8.2

Since Jan 16Pushed 2mo agoCompare

[ Source](https://github.com/beartropy/saml2)[ Packagist](https://packagist.org/packages/beartropy/saml2)[ RSS](/packages/beartropy-saml2/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (8)Dependencies (28)Versions (22)Used By (0)

🛡️ Beartropy SAML2
==================

[](#️-beartropy-saml2)

**Multi-IDP SAML2 Service Provider integration for Laravel using [onelogin/php-saml](https://github.com/onelogin/php-saml)**

Integrate your Laravel app with multiple Identity Providers (Azure AD, Okta, ADFS, etc.)

 [![Latest Stable Version](https://camo.githubusercontent.com/24ecb206aac2d2f9c61f4c76c44d6b43ecada640970eb32e421bdd49f4cb50af/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6265617274726f70792f73616d6c322e7376673f7374796c653d666c61742d73717561726526636f6c6f723d696e6469676f)](https://packagist.org/packages/beartropy/saml2) [![Total Downloads](https://camo.githubusercontent.com/23a089e0b9c96da724e42da6a63dfb2e0e508933f83bd52c860444cb43b72849/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6265617274726f70792f73616d6c322e7376673f7374796c653d666c61742d73717561726526636f6c6f723d626c7565)](https://packagist.org/packages/beartropy/saml2) [![License](https://camo.githubusercontent.com/9ef8ddc431c07cb005a46c0600d17825b5800a062d5b0926dd179573fe59b80b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6265617274726f70792f73616d6c323f7374796c653d666c61742d73717561726526636f6c6f723d736c617465)](https://packagist.org/packages/beartropy/saml2)

Features
--------

[](#features)

- 🔐 Configure your Laravel app as a SAML 2.0 Service Provider
- 🏢 Support for multiple Identity Providers (Azure AD, Okta, ADFS, etc.)
- 🖥️ **Web UI** for first-deploy setup and admin management
- 📦 IDP configuration from environment variables or database
- 🔄 Automatic metadata import from IDP URLs
- 🎯 Event-driven authentication (handle login your way)
- ⚙️ Artisan commands for IDP management
- 🌐 English and Spanish translations included

📚 Documentation
---------------

[](#-documentation)

👉 **[Read the full documentation at beartropy.com/saml2](https://beartropy.com/saml2)**

Installation
------------

[](#installation)

```
composer require beartropy/saml2
```

Publish the configuration and run migrations:

```
php artisan vendor:publish --tag=beartropy-saml2-config
php artisan migrate
```

Quick Start
-----------

[](#quick-start)

### Option A: Using the Setup Wizard (Recommended)

[](#option-a-using-the-setup-wizard-recommended)

After installation, simply navigate to:

```
https://your-app.com/saml2/setup

```

The **First-Deploy Setup Wizard** will guide you through:

1. Displaying your SP metadata (Entity ID, ACS URL, Metadata URL) to share with your IDP administrator
2. Configuring your IDP via:
    - **Metadata URL** - Fetch and parse automatically
    - **Paste XML** - Copy/paste metadata from your IDP
    - **Manual Entry** - Enter Entity ID, SSO URL, Certificate manually

> **Note**: The setup wizard requires authentication (since v0.3.0) and is only accessible before the first IDP is configured. After that, use the Admin Panel.

### Option B: Using Artisan Commands

[](#option-b-using-artisan-commands)

#### 1. Configure your Service Provider

[](#1-configure-your-service-provider)

Add to your `.env`:

```
SAML2_SP_ENTITY_ID=https://your-app.com
```

For signed assertions (recommended), generate SP certificates:

```
php artisan saml2:generate-cert
```

#### 2. Add an Identity Provider

[](#2-add-an-identity-provider)

From a metadata URL:

```
php artisan saml2:create-idp azure --from-url=https://login.microsoftonline.com/.../federationmetadata.xml
```

Or interactively:

```
php artisan saml2:create-idp azure --interactive
```

---

Admin Panel
-----------

[](#admin-panel)

Once configured, manage your SAML2 settings through the web-based admin panel:

```
https://your-app.com/saml2/admin

```

### Features

[](#features-1)

FeatureDescription**Dashboard**View SP metadata and list all configured IDPs**Create IDP**Add new Identity Providers with metadata import**Edit IDP**Modify IDP settings (Entity ID, SSO URL, Certificate, etc.)**Attribute Mapping**Configure per-IDP attribute mapping or use global config**Toggle Status**Activate/deactivate IDPs without deleting**Refresh Metadata**Auto-update IDP settings from metadata URL**Delete IDP**Remove an IDP from database### Admin Configuration

[](#admin-configuration)

Customize the admin panel in `config/beartropy-saml2.php`:

```
// Enable/disable admin panel
'admin_enabled' => env('SAML2_ADMIN_ENABLED', true),

// Route prefix (default: /saml2/admin)
'admin_route_prefix' => env('SAML2_ADMIN_PREFIX', 'saml2/admin'),

// Middleware to protect admin routes
'admin_middleware' => ['web', 'auth'],  // Add 'admin' or custom middleware as needed
```

#### Protecting Admin Routes

[](#protecting-admin-routes)

Add your own authorization middleware:

```
// config/beartropy-saml2.php
'admin_middleware' => ['web', 'auth', 'can:manage-saml'],
```

Or use a Gate in your `AuthServiceProvider`:

```
Gate::define('manage-saml', function ($user) {
    return $user->hasRole('admin');
});
```

---

Handle Authentication Events
----------------------------

[](#handle-authentication-events)

Publish a standard listener:

```
php artisan saml2:publish-listener
```

This creates `app/Listeners/HandleSaml2Login.php`:

```
public function handle(Saml2LoginEvent $event): void
{
    // Find or create user
    $user = User::firstOrCreate(
        ['email' => $event->getEmail()],
        ['name' => $event->getName()]
    );

    // Log them in
    Auth::login($user);
}
```

> **Note**: The listener must be registered manually in your `EventServiceProvider` or with the `#[AsListener]` attribute (Laravel 11+). See the [Setup Guide](docs/en/SETUP.md) for details.

---

Integrate with Your Routes
--------------------------

[](#integrate-with-your-routes)

**Simple** - a login link:

```

    Login with Azure AD

```

**Full Integration** - replacing auth routes:

```
// routes/auth.php

Route::middleware('guest')->group(function () {
    if (app()->environment('local')) {
        // Local login for development
        Route::get('/login', [AuthController::class, 'showLogin'])->name('login');
        Route::post('/login', [AuthController::class, 'authenticate']);
    } else {
        // SAML Login - redirects to IDP
        Route::get('/login', function () {
            return redirect()->route('saml2.login', ['idp' => 'your-idp-key']);
        })->name('login');
    }
});

Route::middleware('auth')->group(function () {
    if (app()->environment('local')) {
        Route::post('/logout', [AuthController::class, 'logout'])->name('logout');
    } else {
        // SAML Logout (SLO)
        Route::match(['get', 'post'], '/logout', function () {
            return redirect()->route('saml2.logout');
        })->name('logout');
    }
});
```

---

Artisan Commands
----------------

[](#artisan-commands)

CommandDescription`saml2:create-idp {key}`Create a new IDP`saml2:list-idps`List all configured IDPs`saml2:test-idp {key}`Test IDP configuration`saml2:delete-idp {key}`Delete an IDP`saml2:generate-cert`Generate SP certificates`saml2:refresh-metadata`Refresh IDP metadata from URLs`saml2:publish-listener`Publish standard login listener`saml2:reset-setup`Reset to first-deploy state### Reset Setup Command

[](#reset-setup-command)

If you need to reconfigure from scratch:

```
# Reset setup state only (keeps IDPs)
php artisan saml2:reset-setup

# Reset setup state AND delete all IDPs
php artisan saml2:reset-setup --with-idps
```

After running this, the setup wizard at `/saml2/setup` will be accessible again.

---

Routes
------

[](#routes)

The package registers these routes:

### SAML Routes

[](#saml-routes)

RouteMethodDescription`/saml2/setup`GETFirst-deploy setup wizard`/saml2/login/{idp?}`GETInitiate SSO login`/saml2/acs`POSTGeneric ACS - auto-detects IDP`/saml2/acs/{idp}`POSTACS with explicit IDP key`/saml2/sls/{idp}`GET/POSTSingle Logout Service`/saml2/metadata`GETSP Metadata XML`/saml2/logout/{idp?}`GETInitiate logout### Admin Routes

[](#admin-routes)

RouteMethodDescription`/saml2/admin`GETAdmin dashboard`/saml2/admin/idp/create`GETCreate IDP form`/saml2/admin/idp`POSTStore new IDP`/saml2/admin/idp/{id}`GET/PUTEdit/update IDP`/saml2/admin/idp/{id}`DELETEDelete IDP`/saml2/admin/idp/{id}/toggle`POSTActivate/deactivate`/saml2/admin/idp/{id}/mapping`GET/POSTAttribute mapping editor`/saml2/admin/idp/{id}/refresh`POSTRefresh metadata---

Attribute Mapping
-----------------

[](#attribute-mapping)

Attribute mapping allows you to normalize SAML attributes from different IDPs.

### Global Mapping (Config)

[](#global-mapping-config)

Set default mapping in `config/beartropy-saml2.php`:

```
'attribute_mapping' => [
    'email' => 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress',
    'name' => 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name',
    'first_name' => 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname',
    'last_name' => 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname',
],
```

### Per-IDP Mapping (Admin Panel or Code)

[](#per-idp-mapping-admin-panel-or-code)

Each IDP can have custom mapping that overrides the global config.

**Via Admin Panel:**

1. Go to `/saml2/admin`
2. Click "Mapping" on any IDP
3. Toggle "Use global mapping" off
4. Add your custom field mappings

**Via Code:**

```
use Beartropy\Saml2\Models\Saml2Idp;

$idp = Saml2Idp::where('key', 'azure')->first();
$idp->attribute_mapping = [
    'email' => 'http://schemas.microsoft.com/identity/claims/emailaddress',
    'name' => 'http://schemas.microsoft.com/identity/claims/displayname',
    'roles' => 'http://schemas.microsoft.com/ws/2008/06/identity/claims/groups',
];
$idp->save();
```

### Using Attributes in Your Listener

[](#using-attributes-in-your-listener)

```
public function handle(Saml2LoginEvent $event): void
{
    // Mapped attributes (uses IDP-specific or falls back to global)
    $email = $event->getEmail();              // Shorthand
    $name = $event->getName();                // Shorthand
    $custom = $event->getAttribute('roles');  // Custom mapped field

    // Raw SAML attributes (always available)
    $rawEmail = $event->getRawAttribute('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress');

    // All data
    $allMapped = $event->attributes;
    $allRaw = $event->rawAttributes;
}
```

---

Configuration Reference
-----------------------

[](#configuration-reference)

### IDP Source

[](#idp-source)

```
// config/beartropy-saml2.php

// 'env' - Single IDP from environment only
// 'database' - Multiple IDPs from database
// 'both' - Check env first, then database
'idp_source' => env('SAML2_IDP_SOURCE', 'database'),
```

### Environment-based IDP

[](#environment-based-idp)

For single IDP setups via `.env`:

```
SAML2_IDP_SOURCE=env
SAML2_IDP_KEY=default
SAML2_IDP_NAME="My IDP"
SAML2_IDP_ENTITY_ID=https://idp.example.com
SAML2_IDP_SSO_URL=https://idp.example.com/sso
SAML2_IDP_SLO_URL=https://idp.example.com/slo
SAML2_IDP_CERT="MIICpDCCAYwCCQ..."
```

### Redirects

[](#redirects)

```
'login_redirect' => env('SAML2_LOGIN_REDIRECT', '/'),
'logout_redirect' => env('SAML2_LOGOUT_REDIRECT', '/'),
'error_redirect' => env('SAML2_ERROR_REDIRECT', '/login'),
```

---

Events
------

[](#events)

### Saml2LoginEvent

[](#saml2loginevent)

Dispatched after successful SAML authentication.

**Properties:**

```
$event->idpKey       // Key of the authenticating IDP
$event->nameId       // SAML NameID (usually email)
$event->attributes   // Mapped attributes (per config)
$event->rawAttributes // Original SAML attributes
$event->sessionIndex // For SLO
```

**Helper Methods:**

```
$event->getEmail();                    // Get email
$event->getName();                     // Get name
$event->getAttribute('field');          // Get mapped attribute
$event->getAttribute('field', 'default'); // With default
$event->getRawAttribute('saml_uri');    // Get raw SAML attribute
$event->toArray();                      // All data as array
```

### Saml2LogoutEvent

[](#saml2logoutevent)

Dispatched after successful SAML logout.

---

Security
--------

[](#security)

Since v0.3.0, the package ships with secure defaults:

- `wantAssertionsSigned` and `wantMessagesSigned` default to `true`
- Setup wizard requires authentication (`setup_middleware`)
- SAML routes include rate limiting (`throttle:60,1`)
- SSRF protection on metadata fetching (`block_private_metadata_urls`)
- Session regeneration after login (prevents session fixation)
- Open redirect protection on `returnTo` parameters

For signing outgoing requests (recommended), generate SP certificates:

```
php artisan saml2:generate-cert
```

Then enable request signing in your config:

```
'security' => [
    'authnRequestsSigned' => true,
    'logoutRequestSigned' => true,
    'signMetadata' => true,
],
```

---

Internationalization
--------------------

[](#internationalization)

The package includes English and Spanish translations. To publish and customize:

```
php artisan vendor:publish --tag=beartropy-saml2-lang
```

This creates files in `lang/vendor/beartropy-saml2/`.

---

Customizing Views
-----------------

[](#customizing-views)

To customize the setup wizard or admin panel views:

```
php artisan vendor:publish --tag=beartropy-saml2-views
```

This publishes views to `resources/views/vendor/beartropy-saml2/`.

> **Note**: The UI is vanilla HTML/CSS (no Tailwind or Livewire dependencies), so it works with any Laravel stack.

---

Documentation
-------------

[](#documentation)

For more detailed information, please refer to the following guides:

- **[English Documentation](docs/en/README.md)**
- **[Documentación en Español](docs/es/README.md)**

Includes detailed guides for [Configuration](docs/en/CONFIG.md), [Installation](docs/en/INSTALL.md), [Initial Setup](docs/en/SETUP.md), and the [Admin UI](docs/en/UI.md).

---

License
-------

[](#license)

MIT License - see [LICENSE.md](LICENSE.md)

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance87

Actively maintained with recent releases

Popularity17

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~8 days

Recently: every ~20 days

Total

21

Last Release

52d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/222533003?v=4)[beartropy](/maintainers/beartropy)[@beartropy](https://github.com/beartropy)

![](https://www.gravatar.com/avatar/a2e1b494339d1174075516870c7f6f8ddb4aa78e364e5f709fbf4b6c962ac7e0?d=identicon)[smithingdev](/maintainers/smithingdev)

---

Top Contributors

[![beartropy](https://avatars.githubusercontent.com/u/222533003?v=4)](https://github.com/beartropy "beartropy (34 commits)")

---

Tags

laravelSSOsamlSAML2idpsponeloginbeartropy

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/beartropy-saml2/health.svg)

```
[![Health](https://phpackages.com/badges/beartropy-saml2/health.svg)](https://phpackages.com/packages/beartropy-saml2)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.4M354](/packages/psalm-plugin-laravel)[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.6k31.8M162](/packages/laravel-cashier)[api-platform/laravel

API Platform support for Laravel

58190.1k21](/packages/api-platform-laravel)[scaler-tech/laravel-saml2

SAML2 Service Provider integration for Laravel applications, based on OneLogin toolkit

281162.9k](/packages/scaler-tech-laravel-saml2)[fleetbase/core-api

Core Framework and Resources for Fleetbase API

1239.7k25](/packages/fleetbase-core-api)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
