A Laravel package for SSO integration with Authentik using SCIM provisioning.
- SCIM User Provisioning: Automatically sync users from Authentik to your Laravel application
- SSO Authentication: OAuth/OIDC-based single sign-on with Authentik
- Single Logout (SLO): Back-channel logout support to invalidate sessions when users log out from Authentik
- Configurable: Control user creation, updates, deletion, and field mappings via configuration
- Session Management: Automatically invalidate sessions when users are blocked
- Flexible Field Mappings: Map Authentik/SCIM fields to your custom User model fields
- PHP 8.1 or higher
- Laravel 10.0, 11.0, 12.0, or 13.0
- Authentik instance with SCIM and OAuth configured
composer require quadcompanies/quadssophp artisan vendor:publish --tag=quadsso-configThis will create config/quadsso.php where you can customize all settings.
The package includes a migration to add required fields to your users table:
php artisan migrateThis adds:
scim_external_id- Stores the Authentik user UUIDemail_verified_at- Standard Laravel email verification field (if not already present)status- User status field (default: 'active') for SCIM user blocking
The package works out-of-the-box with Laravel's standard users table (single name field). SCIM's givenName and familyName are automatically combined into the name column.
Ensure your User model includes the necessary fields in $fillable:
protected $fillable = [
'email',
'password',
'scim_external_id',
'email_verified_at',
'status', // or whatever field you use for user status
'name_first',
'name_last',
'name_middle',
'phone_cell',
'email_secondary',
// ... other fields
];Add the following to your config/services.php:
'authentik' => [
'client_id' => env('AUTHENTIK_CLIENT_ID'),
'client_secret' => env('AUTHENTIK_CLIENT_SECRET'),
'redirect' => env('AUTHENTIK_REDIRECT_URI'),
'base_url' => env('AUTHENTIK_BASE_URL'),
'jwks_uri' => env('AUTHENTIK_JWKS_URI'),
'logout_url' => env('AUTHENTIK_LOGOUT_URL'),
],Add these to your .env file:
# Authentik OAuth/OIDC Configuration
AUTHENTIK_CLIENT_ID=your-client-id
AUTHENTIK_CLIENT_SECRET=your-client-secret
AUTHENTIK_REDIRECT_URI=https://your-app.com/auth/sso/callback
AUTHENTIK_BASE_URL=https://authentik.your-domain.com
AUTHENTIK_JWKS_URI=https://authentik.your-domain.com/application/o/your-app/jwks/
AUTHENTIK_LOGOUT_URL=https://authentik.your-domain.com/application/o/your-app/end-session/
# SCIM Configuration
SCIM_ENABLED=true
SCIM_BASE_PATH=/scim
SCIM_BEARER_TOKEN=your-secure-random-token
# SCIM Feature Flags
SCIM_AUTO_PROVISION=true
SCIM_ALLOW_USER_CREATION=true
SCIM_ALLOW_USER_UPDATES=true
SCIM_ALLOW_USER_DELETION=true
SCIM_INVALIDATE_SESSIONS_ON_BLOCK=true
# SCIM User Defaults
SCIM_DEFAULT_USER_LEVEL=user
SCIM_DEFAULT_USER_STATUS=active
# SSO Configuration
SSO_AUTO_VERIFY_EMAIL=true
SSO_REDIRECT_AFTER_LOGIN=/home
SSO_REDIRECT_AFTER_FAILURE=/login
SSO_ENABLE_SLO=true
SSO_INVALIDATE_REMEMBER_TOKENS_ON_SLO=true
# Logging (optional, for debugging)
QUADSSO_LOG_SCIM_REQUESTS=false
QUADSSO_LOG_SSO_EVENTS=false
QUADSSO_LOG_SLO_EVENTS=trueIf you want to customize the SCIM server configuration:
php artisan vendor:publish --provider="ArieTimmerman\Laravel\SCIMServer\SCIMServerServiceProvider" --tag=scimThen update config/scim.php:
return [
'publish_routes' => true,
'omit_main_schema_in_return' => false,
'omit_null_values' => true,
'path' => env('SCIM_BASE_PATH', '/scim'),
'domain' => env('SCIM_DOMAIN', null),
'middleware' => [\QuadCompanies\QuadSSO\Middleware\ScimBearerToken::class],
'public_middleware' => [],
'bearer_token' => env('SCIM_BEARER_TOKEN'),
'pagination' => [
'defaultPageSize' => 10,
'maxPageSize' => 100,
'cursorPaginationEnabled' => true,
],
'authenticationSchemes' => [
'oauthbearertoken',
],
];Customize how SCIM/Authentik fields map to your User model in config/quadsso.php:
'field_mappings' => [
'email' => 'email',
'external_id' => 'scim_external_id',
'email_verified_at' => 'email_verified_at',
'name_first' => 'name_first',
'name_last' => 'name_last',
'name_middle' => 'name_middle',
'phone_cell' => 'phone_cell',
'email_secondary' => 'email_secondary',
],Configure how user status is handled:
'scim' => [
'user_status_field' => 'status', // Your User model's status field
'active_status_value' => 'active', // Value that means "active"
'blocked_status_value' => 'blocked', // Value that means "blocked"
'invalidate_sessions_on_block' => true, // Kill sessions when user is blocked
],Control what SCIM operations are allowed:
'scim' => [
'allow_user_creation' => true, // Allow creating new users via SCIM
'allow_user_updates' => true, // Allow updating existing users via SCIM
'allow_user_deletion' => true, // Allow blocking users via SCIM (active=false)
],In Authentik:
- Go to Applications → Providers → Create
- Select OAuth2/OpenID Provider
- Configure:
- Name: Your App Name
- Client Type: Confidential
- Redirect URIs:
https://your-app.com/auth/sso/callback - Signing Key: Choose an appropriate certificate
- Enable Back-Channel Logout URL:
https://your-app.com/auth/sso/logout
- Go to Applications → Create
- Configure:
- Name: Your App Name
- Slug: your-app
- Provider: Select the provider created above
- Go to Applications → Providers → Create
- Select SCIM Provider
- Configure:
- Name: Your App SCIM
- URL:
https://your-app.com/scim/v2 - Token: Your
SCIM_BEARER_TOKENvalue - Exclude service accounts: Checked
- Edit your application
- In the Backchannel Providers section, add your SCIM provider
Map additional Authentik user fields to SCIM attributes as needed.
Users can initiate SSO login by visiting:
https://your-app.com/auth/sso
Or add a login button to your login page:
<a href="{{ route('sso.redirect') }}" class="btn btn-primary">
Login with SSO
</a>The package automatically registers these routes:
GET /auth/sso- Initiate SSO login (namedsso.redirect)GET /auth/sso/callback- OAuth callback (namedsso.callback)POST /auth/sso/logout- Back-channel logout endpoint (namedsso.logout)
SCIM routes are automatically registered by the laravel-scim-server package:
GET /scim/v2/Users- List usersGET /scim/v2/Users/{id}- Get userPOST /scim/v2/Users- Create userPUT /scim/v2/Users/{id}- Update userPATCH /scim/v2/Users/{id}- Patch userDELETE /scim/v2/Users/{id}- Delete user (sets active=false)
- User created in Authentik → SCIM creates user in Laravel
- User updated in Authentik → SCIM updates user in Laravel
- User blocked in Authentik → SCIM sets user status to "blocked" and kills sessions
- User logs in → OAuth redirects to Authentik → User authenticates → Callback creates session
- User logs out from Authentik → Authentik sends back-channel logout JWT
- Laravel verifies JWT → Finds user by
scim_external_id - Sessions deleted → User is logged out from all devices
- Remember tokens cycled → "Remember me" cookies are invalidated
By default, QuadSSO maps SCIM name fields to Laravel's standard single name column. If you want separate fields for first/last/middle names and additional contact fields:
1. Run the optional extended fields migration:
php artisan migrate --path=vendor/quadcompanies/quadsso/database/migrations/2024_01_01_000002_add_extended_quadsso_fields_to_users_table.phpThis adds: name_first, name_last, name_middle, phone_cell, email_secondary
2. Update config/quadsso.php to enable these mappings:
'field_mappings' => [
'email' => 'email',
'external_id' => 'scim_external_id',
'email_verified_at' => 'email_verified_at',
// Enable extended name fields
'name_first' => 'name_first', // Changed from null
'name_last' => 'name_last', // Changed from null
'name_middle' => 'name_middle', // Changed from null
'name' => null, // Disable single name field
// Enable contact fields
'phone_cell' => 'phone_cell', // Changed from null
'email_secondary' => 'email_secondary', // Changed from null
],3. Add to User model's $fillable:
protected $fillable = [
'email',
'password',
'scim_external_id',
'email_verified_at',
'status',
'name_first',
'name_last',
'name_middle',
'phone_cell',
'email_secondary',
];
⚠️ Schema Validation: The package automatically checks if configured field mappings exist in your database schema. If you see warnings in your logs about missing columns, either run the extended migration or set those mappings tonullin the config.
If you use a custom user model, update config/quadsso.php:
'user_model' => \App\Models\CustomUser::class,If you want to manually handle user creation instead of the automatic observer:
'scim' => [
'auto_provision' => false,
],Change where users are redirected after login/logout:
'sso' => [
'redirect_after_login' => '/dashboard',
'redirect_after_failure' => '/login',
],If your User model has custom fields, add them to the SCIM configuration by extending QuadSSOScimConfig:
namespace App\Scim;
use QuadCompanies\QuadSSO\Scim\QuadSSOScimConfig;
class CustomScimConfig extends QuadSSOScimConfig
{
// Override methods to add custom field mappings
}Then bind your custom config in AppServiceProvider:
use ArieTimmerman\Laravel\SCIMServer\SCIMConfig;
use App\Scim\CustomScimConfig;
public function register(): void
{
$this->app->bind(SCIMConfig::class, CustomScimConfig::class);
}Set these in your .env:
QUADSSO_LOG_SCIM_REQUESTS=true
QUADSSO_LOG_SSO_EVENTS=true
QUADSSO_LOG_SLO_EVENTS=trueThen check storage/logs/laravel.log for detailed logs.
Make sure SCIM_BEARER_TOKEN is set in your .env file.
The user hasn't been provisioned via SCIM yet. Make sure:
- SCIM provider is configured in Authentik
- SCIM provider is bound to your application
- User exists in Authentik and is assigned to the application
The user's status field is set to the blocked value. Check:
- User's status in the database
SCIM_ACTIVE_STATUS_VALUEandSCIM_BLOCKED_STATUS_VALUEsettings
Make sure:
SSO_ENABLE_SLO=truein your.env- Back-channel logout URL is configured in Authentik
- JWKS URI is correct and accessible
The package automatically secures SCIM endpoints with bearer token authentication. The ScimBearerToken middleware is auto-configured to protect all /scim/v2/* routes.
To verify security is working:
# Should return 401 Unauthorized
curl http://your-app.local/scim/v2/Users
# Should return user data (with valid token)
curl -H "Authorization: Bearer your-token-here" http://your-app.local/scim/v2/Users- ✅ Always use HTTPS in production
- ✅ Generate a strong random token for
SCIM_BEARER_TOKEN:php artisan tinker --execute="echo \Illuminate\Support\Str::random(64);" - ✅ Keep your
SCIM_BEARER_TOKENsecure - treat it like a password - ✅ Regularly rotate your Authentik client secrets and SCIM tokens
- ✅ Monitor your logs for unauthorized SCIM access attempts (enable
QUADSSO_LOG_SCIM_REQUESTS=true) - ✅ Use firewall rules to restrict SCIM endpoint access to Authentik's IP addresses if possible
MIT
For issues and questions, please open an issue on GitHub.
Built by Quad Companies using:
- laravel-scim-server by Arie Timmerman
- socialite by Laravel
- socialiteproviders/authentik by SocialiteProviders