quadcompanies / quadsso
A Laravel package for SSO integration with Authentik using SCIM provisioning
Requires
- php: ^8.1|^8.2|^8.3
- arietimmerman/laravel-scim-server: ^1.4
- firebase/php-jwt: ^6.0|^7.0
- illuminate/contracts: ^10.0|^11.0|^12.0|^13.0
- laravel/socialite: ^5.0
- socialiteproviders/authentik: ^5.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpunit/phpunit: ^10.0|^11.0
README
A Laravel package for SSO integration with Authentik using SCIM provisioning.
Features
- 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
Requirements
- PHP 8.1 or higher
- Laravel 10.0, 11.0, 12.0, or 13.0
- Authentik instance with SCIM and OAuth configured
Installation
1. Install via Composer
composer require quadcompanies/quadsso
2. Publish Configuration
php artisan vendor:publish --tag=quadsso-config
This will create config/quadsso.php where you can customize all settings.
3. Run Migrations
The package includes a migration to add required fields to your users table:
php artisan migrate
This 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.
4. Update Your User Model
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 ];
5. Add Authentik to Services Config
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'), ],
6. Configure Environment Variables
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=true
7. Publish SCIM Configuration (Optional)
If you want to customize the SCIM server configuration:
php artisan vendor:publish --provider="ArieTimmerman\Laravel\SCIMServer\SCIMServerServiceProvider" --tag=scim
Then 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', ], ];
Configuration
Field Mappings
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', ],
User Status Management
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 ],
Feature Flags
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) ],
Authentik Setup
1. Create an OAuth Provider
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
2. Create an Application
- Go to Applications → Create
- Configure:
- Name: Your App Name
- Slug: your-app
- Provider: Select the provider created above
3. Set Up SCIM
- 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
4. Bind SCIM Provider to Application
- Edit your application
- In the Backchannel Providers section, add your SCIM provider
5. Configure Property Mappings (Optional)
Map additional Authentik user fields to SCIM attributes as needed.
Usage
Login via SSO
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>
Routes
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)
How It Works
User Provisioning Flow
- 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
Single Logout Flow
- 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
Customization
Extended User Fields (Optional)
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.php
This 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 to
nullin the config.
Custom User Model
If you use a custom user model, update config/quadsso.php:
'user_model' => \App\Models\CustomUser::class,
Disable Auto-Provisioning
If you want to manually handle user creation instead of the automatic observer:
'scim' => [ 'auto_provision' => false, ],
Custom Redirect Routes
Change where users are redirected after login/logout:
'sso' => [ 'redirect_after_login' => '/dashboard', 'redirect_after_failure' => '/login', ],
Additional Field Mappings
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); }
Troubleshooting
Enable Debug Logging
Set these in your .env:
QUADSSO_LOG_SCIM_REQUESTS=true QUADSSO_LOG_SSO_EVENTS=true QUADSSO_LOG_SLO_EVENTS=true
Then check storage/logs/laravel.log for detailed logs.
Common Issues
"SCIM bearer token not configured"
Make sure SCIM_BEARER_TOKEN is set in your .env file.
"No account found for this identity"
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
"Your account has been suspended"
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
Sessions not being invalidated on logout
Make sure:
SSO_ENABLE_SLO=truein your.env- Back-channel logout URL is configured in Authentik
- JWKS URI is correct and accessible
Security
🔒 SCIM Endpoint Protection
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
Best Practices
- ✅ 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
License
MIT
Support
For issues and questions, please open an issue on GitHub.
Credits
Built by Quad Companies using:
- laravel-scim-server by Arie Timmerman
- socialite by Laravel
- socialiteproviders/authentik by SocialiteProviders