SAML2 SSO
Kompass supports enterprise Single Sign-On via SAML2. You can configure one or more Identity Providers (IdPs) so users authenticate with their organisation's existing credentials — no separate password required.
Prerequisite
This feature requires the scaler-tech/laravel-saml2 package. Kompass detects it via Features::hasSaml2() and shows the SSO settings panel only when it is installed.
Setup
Step 1. Install dependency
composer require scaler-tech/laravel-saml2Step 2. Publish the configuration file
php artisan vendor:publish --provider="Slides\Saml2\ServiceProvider"Step 3. Run migrations
php artisan migrateStep 4. Handle the login
The package validates the IdP response and fires a SignedIn event, but it does not log anyone in by itself. You have to map the SAML identity to a local user and call Auth::login — without this step SSO appears to "do nothing" after a successful authentication at the IdP.
Create a listener (auto-discovered from app/Listeners):
// app/Listeners/SamlLoginListener.php
namespace App\Listeners;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Slides\Saml2\Events\SignedIn;
class SamlLoginListener
{
public function handle(SignedIn $event): void
{
$samlUser = $event->getSaml2User();
// Most IdPs (Google Workspace, Azure AD) send the e-mail as the NameID.
$email = $samlUser->getUserId();
if (! is_string($email) || ! filter_var($email, FILTER_VALIDATE_EMAIL)) {
return;
}
// Auto-provision: create the user on first login.
$user = User::firstOrNew(['email' => $email]);
if (! $user->exists) {
$user->name = Str::before($email, '@');
$user->password = Hash::make(Str::random(40)); // unused – login is via SSO
$user->email_verified_at = now();
$user->save();
}
Auth::login($user, remember: true);
}
}Restrict who may sign in
For "existing users only", drop the firstOrNew block and return when the user does not exist. To restrict by domain, check Str::after($email, '@') against an allow-list before provisioning.
For the login to persist, the SAML routes need the web middleware group (it starts the session). In config/saml2.php:
'routesMiddleware' => ['web'],Because the IdP POSTs to the ACS/SLS routes without a CSRF token, exclude them from CSRF verification. In bootstrap/app.php (Laravel 11+):
->withMiddleware(function (Middleware $middleware) {
$middleware->validateCsrfTokens(except: [
'saml2/*',
]);
})Laravel 11+ uses auto-discovery
Listeners in app/Listeners are registered automatically. Do not also add the listener to EventServiceProvider::$listen, or it will run twice.
Step 5. Configure environment variables
Set the redirect targets and any optional settings in your .env. These are read by config/saml2.php:
# Where users land after login / logout / on error (fall back to "/" if unset)
SAML2_LOGIN_URL="${APP_URL}/admin/dashboard"
SAML2_LOGOUT_URL="${APP_URL}"
SAML2_ERROR_URL="${APP_URL}/login"
# Print the toolkit's error details (defaults to APP_DEBUG)
SAML2_DEBUG=false| Variable | Purpose |
|---|---|
SAML2_LOGIN_URL | Redirect after a successful login (e.g. the admin dashboard) |
SAML2_LOGOUT_URL | Redirect after logout |
SAML2_ERROR_URL | Redirect when the assertion fails validation |
SAML2_DEBUG | Surface the exact SAML error reason — enable only while debugging |
Set per environment
.env is not committed. Add these variables on every server (staging, production). Because the URLs derive from APP_URL, make sure APP_URL is the real domain in production.
Configuring an Identity Provider
Go to Settings → SAML2 SSO and click Add Identity Provider. Fill in the fields for your IdP:
| Field | Description |
|---|---|
| Name | Display name for this IdP |
| Entity ID | IdP's unique entity identifier (URI) |
| Login URL | IdP SSO endpoint |
| Logout URL | IdP SLO endpoint (optional) |
| x509 Certificate | IdP's public certificate for signature verification |
| NameID Format | persistent, transient, email, or unspecified |
Importing Metadata
Instead of filling in the fields manually, you can import the IdP configuration directly from its metadata:
- URL — Paste the metadata URL; Kompass fetches and parses it automatically.
- XML file — Upload the metadata XML from your IdP's admin panel.
- Direct paste — Paste the XML directly into the form.
Prefer the metadata URL
Most enterprise IdPs (Okta, Azure AD, Google Workspace) publish a metadata URL in their admin console. Using the URL import keeps your configuration in sync without manual updates.
Service Provider URLs (register these in your IdP)
Your IdP needs to know where to send users and assertions. Each tenant exposes its own endpoints based on its UUID (shown in the SAML2 settings panel). Register the following in the IdP's app configuration:
| IdP field | Value |
|---|---|
| ACS / Reply / Assertion Consumer Service URL | https://<your-domain>/saml2/<tenant-uuid>/acs |
| Entity ID / Audience / Metadata URL | https://<your-domain>/saml2/<tenant-uuid>/metadata |
| Single Logout URL (optional) | https://<your-domain>/saml2/<tenant-uuid>/sls |
Match APP_URL to the real domain
These URLs are built from APP_URL. If you test locally (e.g. https://app.test) the generated ACS URL points there too. Set APP_URL to the production domain before registering the app with your IdP, or the IdP will reject the assertion destination.
Login Button
Add an SSO button to the Kompass login page under Settings → SAML2 SSO → Login Button:
| Option | Description |
|---|---|
| Label | Button text (e.g. "Sign in with Okta") |
| Icon | SVG icon shown next to the label |
| Enabled | Toggle the button on or off without deleting the configuration |
Multiple Tenants
Each IdP is represented as a tenant. You can create, edit, and delete tenants from the SAML2 settings panel. Kompass supports multiple tenants for organisations that operate more than one IdP — for example, a parent company and an acquired subsidiary each with their own identity infrastructure.
Security
- Kompass verifies assertions against the configured x509 certificate.
- Role middleware enforces access control after SSO login completes.
- Only administrators can manage the SSO configuration.
Troubleshooting
Google: 403. app_not_configured_for_user
Service is not configured for this user.
This error comes from Google, not from Kompass — the SAML hand-off worked, but Google declined to issue an assertion. The custom SAML app exists in the Google Admin console but is not enabled for the account that is signing in.
Fix it in the Google Admin console:
- Go to admin.google.com → Apps → Web and mobile apps.
- Open your custom SAML app (the one whose Entity ID matches your tenant).
- Open User access.
- Set the service status to ON for everyone, or turn it on for the specific Organisational Unit / group the users belong to.
- Save. Changes can take a few minutes to propagate.
Then retry with an account inside your Workspace domain — a personal Gmail account is not part of the organisation and will trigger the same error.
Other common errors
| Symptom | Likely cause | Fix |
|---|---|---|
419 Page Expired on the ACS callback | The saml2/* routes are behind CSRF protection | Exclude saml2/* from CSRF verification |
| Login succeeds at the IdP but the user is not logged in | No listener handles the Slides\Saml2\Events\SignedIn event, or the SAML routes lack the web middleware (no session) | Add a SignedIn listener that maps the SAML identity to a local user and calls Auth::login; set routesMiddleware to ['web'] |
Invalid issuer / Signature validation failed | The IdP Entity ID or x509 certificate does not match the tenant | Re-import the IdP metadata so the certificate and issuer are in sync |
Invalid destination / assertion rejected | The ACS URL registered at the IdP does not match the app's APP_URL | Align APP_URL with the domain registered in the IdP |
Read the real reason
Validation failures are logged with key saml2.error_detail. Temporarily set SAML2_DEBUG=true (or APP_DEBUG=true) to surface the exact reason returned by the SAML toolkit.