mi-lopez/laravel-sso is a Laravel package for simple php sso integration for laravel.
It currently has 63 GitHub stars and 1.076 downloads on Packagist (latest version v11.0.0).
Install it with composer require mi-lopez/laravel-sso.
Discover more Laravel packages by mi-lopez
or browse all Laravel packages to compare alternatives.
Last updated
Single Sign-On (SSO) integration for Laravel. One central server authenticates users; multiple broker apps share that login session. Based on zefy/php-simple-sso.
| Package | Laravel | PHP | Branch | |---------|---------|--------|---------------------------------------------------------| | 8.x | 8.x | 7.4+ | 8.x | | 11.x | 11.x | 8.2+ | 11.x |
composer require mi-lopez/laravel-sso
Publish the config:
php artisan vendor:publish --provider="Zefy\LaravelSSO\SSOServiceProvider"
This creates config/laravel-sso.php. Set type to either server or broker depending on the role of the application.
In config/laravel-sso.php:
'type' => 'server',
The package ships with two migrations (brokers and broker_user). Run them:
php artisan migrate
The server endpoints (/api/sso/*) need access to sessions. In bootstrap/app.php:
->withMiddleware(function (Middleware $middleware) {
$middleware->api(prepend: [
\Illuminate\Session\Middleware\StartSession::class,
]);
})
For each broker app you plan to run, generate a name and secret:
php artisan sso:broker:create my-broker
The command prints the secret. Copy it — the broker app needs it.
config/laravel-sso.php lets you choose which user attributes are sent back. Defaults to id only:
'userFields' => [
'id' => 'id',
'email' => 'email',
'name' => 'name',
],
In config/laravel-sso.php:
'type' => 'broker',
In .env:
SSO_SERVER_URL=https://sso.example.com
SSO_BROKER_NAME=my-broker
SSO_BROKER_SECRET=<secret-printed-by-sso:broker:create>
SSOAutoLogin must run before the auth middleware so it can log the user in transparently. Use prependToPriorityList in bootstrap/app.php:
->withMiddleware(function (Middleware $middleware) {
$middleware->prependToPriorityList(
before: \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
prepend: \Zefy\LaravelSSO\Middleware\SSOAutoLogin::class,
);
})
Then attach the middleware to your protected routes (typically alongside auth):
use Zefy\LaravelSSO\Middleware\SSOAutoLogin;
Route::middleware([SSOAutoLogin::class, 'auth'])->group(function () {
Route::get('/dashboard', fn () => view('dashboard'))->name('dashboard');
// ...
});
Why a priority entry? Laravel's default priority list places
Authenticatenear the end, which meansauthwould otherwise short-circuit a guest with a redirect to/loginbeforeSSOAutoLogingets a chance to log them in via SSO. PinningSSOAutoLoginbeforeAuthenticatesRequests(the contractauthimplements) fixes the order without copying the whole priority list.
You need to override the login form controller so credentials go through the broker. With Laravel Breeze, replace app/Http/Controllers/Auth/AuthenticatedSessionController.php with:
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\LoginRequest;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Zefy\LaravelSSO\LaravelSSOBroker;
class AuthenticatedSessionController extends Controller
{
public function create(): View
{
// Ensure the broker token cookie exists before the user submits the form,
// so the POST hits the SSO server with a valid attached session.
new LaravelSSOBroker;
return view('auth.login');
}
public function store(LoginRequest $request): RedirectResponse
{
$broker = new LaravelSSOBroker;
if (! $broker->login($request->input('email'), $request->input('password'))) {
return back()->withErrors(['email' => __('auth.failed')])->onlyInput('email');
}
$userInfo = $broker->getUserInfo();
if (! empty($userInfo['data']['id'])) {
auth()->loginUsingId($userInfo['data']['id']);
}
$request->session()->regenerate();
return redirect()->intended(route('dashboard', absolute: false));
}
public function destroy(Request $request): RedirectResponse
{
(new LaravelSSOBroker)->logout();
auth()->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}
}
For other auth scaffolding (Jetstream, Fortify, custom): wherever you handle the login POST, replace the local Auth::attempt with $broker->login(...) and call $broker->logout() on logout.
When the broker calls auth()->loginUsingId($id), Laravel looks for the user in the broker's database. The simplest setup is to keep the same users table on each broker as on the server (same id, same email). If you don't want that, you can:
| Command | Description |
|-------------------------------|-----------------------|
| sso:broker:create {name} | Create a new broker. |
| sso:broker:delete {name} | Delete a broker. |
| sso:broker:list | List all brokers. |
config/laravel-sso.php:
| Key | Default | Description |
|----------------------|--------------------------|---------------------------------------------------------------------|
| type | server | server or broker. |
| usersModel | App\Models\User::class | Eloquent model used by the server to look up users. |
| brokersModel | Broker::class | Eloquent model used by the server to look up brokers. |
| brokersUserModel | BrokerUser::class | Pivot model linking users and brokers (optional, for custom flows). |
| brokersTable | brokers | Table name backing brokersModel. |
| brokerUserTable | broker_user | Table name backing brokersUserModel. |
| userFields | ['id' => 'id'] | Map of payload-key → user-column for fields sent to brokers. |
| serverUrl | env SSO_SERVER_URL | (broker) URL of the SSO server. |
| brokerName | env SSO_BROKER_NAME | (broker) Broker name registered on the server. |
| brokerSecret | env SSO_BROKER_SECRET | (broker) Secret printed by sso:broker:create. |
composer test
composer lint
MIT. See LICENSE.md.