admin9 / laravel-oidc-client
Laravel OIDC Client package with PKCE support for SSO/SLO authentication
Fund package maintenance!
admin9-labs
Installs: 1
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/admin9/laravel-oidc-client
Requires
- php: ^8.2
- illuminate/cache: ^11.0||^12.0
- illuminate/http: ^11.0||^12.0
- illuminate/routing: ^11.0||^12.0
- illuminate/support: ^11.0||^12.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.8
- orchestra/testbench: ^10.0.0||^9.0.0
- pestphp/pest: ^3.0||^4.0
- pestphp/pest-plugin-arch: ^3.0||^4.0
- pestphp/pest-plugin-laravel: ^3.0||^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
README
A Laravel package for OIDC (OpenID Connect) authentication with PKCE support, designed for SSO/SLO (Single Sign-On/Single Logout) flows.
Features
- OIDC Authorization Code Flow with PKCE (Proof Key for Code Exchange)
- State parameter validation for CSRF protection
- One-time exchange codes with configurable TTL
- Configurable user mapping (column names, userinfo→attribute mapping)
- OidcService for Auth Server token revocation (use in your logout)
- Configurable routes and middleware
- Rate limiting on sensitive endpoints
- Publishable translation files for error messages
Requirements
- PHP 8.2+
- Laravel 11.x or 12.x
- JWT authentication package (e.g.,
php-open-source-saver/jwt-authortymon/jwt-auth) configured with anapiguard
Installation
composer require admin9/laravel-oidc-client
Publish Configuration
php artisan vendor:publish --tag="oidc-client-config"
Publish Migrations
php artisan vendor:publish --tag="oidc-client-migrations"
php artisan migrate
Publish Translations (optional)
php artisan vendor:publish --tag="oidc-client-translations"
Configuration
The config key is oidc-client.
Configure your OIDC provider in .env:
# Auth Server Configuration OIDC_AUTH_SERVER_HOST=https://auth.example.com OIDC_CLIENT_ID=your-client-id OIDC_CLIENT_SECRET=your-client-secret OIDC_REDIRECT_URI=http://localhost/auth/callback # Frontend URL (for redirects after auth) OIDC_FRONTEND_URL=http://localhost:3000 # Optional: Customize scopes OIDC_SCOPES="openid profile email" # Optional: Exchange code TTL (minutes) OIDC_EXCHANGE_CODE_TTL=5 # Optional: JWT guard name OIDC_JWT_GUARD=api
User Model Setup
Your User model needs the following fields (column names are configurable via user_mapping):
// Migration (default column names) Schema::table('users', function (Blueprint $table) { $table->string('oidc_sub')->nullable()->unique(); $table->text('auth_server_refresh_token')->nullable(); $table->string('password')->nullable()->change(); // For OIDC-only users });
Add the encrypted cast for the refresh token:
// app/Models/User.php protected function casts(): array { return [ 'auth_server_refresh_token' => 'encrypted', // ... ]; } protected $fillable = [ 'name', 'email', 'password', 'oidc_sub', 'auth_server_refresh_token', ]; protected $hidden = [ 'password', 'auth_server_refresh_token', ];
User Mapping Configuration
Customize how OIDC userinfo claims map to your User model in config/oidc-client.php:
'user_mapping' => [ 'identifier_column' => 'oidc_sub', // DB column for OIDC subject ID 'identifier_claim' => 'sub', // Userinfo claim used as identifier 'refresh_token_column' => 'auth_server_refresh_token', 'attributes' => [ 'name' => fn ($userinfo) => $userinfo['name'] ?? $userinfo['email'], 'email' => fn ($userinfo) => $userinfo['email'], ], ],
Routes
The package registers the following routes:
| Method | URI | Name | Description |
|---|---|---|---|
| GET | /auth/redirect |
oidc.redirect |
Initiates OIDC authorization |
| GET | /auth/callback |
oidc.callback |
Handles Auth Server callback |
| POST | /api/auth/exchange |
oidc.exchange |
Exchanges code for JWT token |
Note: Logout is NOT provided by the package. You should implement it in your AuthController using OidcService.
OidcService
The package provides OidcService for use in your controllers:
use Admin9\OidcClient\Services\OidcService; class AuthController extends Controller { public function logout(Request $request, OidcService $oidcService): JsonResponse { $user = $request->user(); // Revoke Auth Server token if user logged in via OIDC // (Does nothing if user has no auth_server_refresh_token) $oidcService->revokeAuthServerToken($user); // Blacklist JWT auth('api')->logout(); // Return SSO logout URL for OIDC users $data = ['message' => 'Successfully logged out']; if ($oidcService->isOidcUser($user)) { $data['logout_url'] = $oidcService->getSsoLogoutUrl(); } return response()->json($data); } }
OidcService Methods
| Method | Description |
|---|---|
revokeAuthServerToken($user) |
Revokes Auth Server token and clears stored refresh token |
getSsoLogoutUrl() |
Returns the SSO logout URL for frontend redirect |
isOidcUser($user) |
Checks if user authenticated via OIDC |
findOrCreateUser($userData, $refreshToken) |
Creates or updates a local user from OIDC userinfo |
Events
The package dispatches events you can listen to in your application:
| Event | Payload | When |
|---|---|---|
OidcUserAuthenticated |
$user, $userInfo, $isNewUser |
After successful OIDC callback and user creation |
OidcTokenExchanged |
$user |
After exchange code is swapped for a JWT |
OidcAuthFailed |
$errorCode, $errorMessage |
On authorization denial or server error |
// Example: Send welcome email to new OIDC users use Admin9\OidcClient\Events\OidcUserAuthenticated; class SendWelcomeEmail { public function handle(OidcUserAuthenticated $event): void { if ($event->isNewUser) { // Send welcome email to $event->user } } }
Authentication Flow
Frontend API Package Auth Server
│ │ │ │
│ 1. Login │ │ │
│──────────────>│ │ │
│ │ 2. /auth/redirect │
│ │──────────────>│ │
│ │ │ 3. PKCE+State │
│ │ │ 4. Redirect │
│<─────────────────────────────────────────────>│
│ │ │ │
│ 5. User authenticates with Auth Server │
│<─────────────────────────────────────────────>│
│ │ │ │
│ │ │ 6. /callback │
│ │ │<──────────────│
│ │ │ 7-10. Validate│
│ │ │ & exchange │
│ 12. Redirect with code │ │
│<──────────────────────────────│ │
│ │ │ │
│ 13. POST /api/auth/exchange │ │
│──────────────>│──────────────>│ │
│ │ │14-15. JWT │
│<──────────────│<──────────────│ │
│ 16. JWT Token │ │ │
Security Features
- PKCE (Proof Key for Code Exchange): SHA-256 code challenge prevents authorization code interception
- State Parameter: 40-character random string prevents CSRF attacks
- One-Time Exchange Codes: UUID format, configurable expiration (default 5 minutes)
- Encrypted Refresh Tokens: Auth Server refresh tokens are encrypted at rest
- Rate Limiting: All sensitive endpoints are rate-limited (redirect, callback, exchange)
- OidcService: Provides Auth Server token revocation for complete logout
Documentation
- Authentication Flow — Full sequence diagram and step-by-step explanation
- Configuration Reference — All config options with env vars and defaults
- User Model Setup — Migration, fillable, casts, and custom column names
- OidcService API — Methods for logout, token revocation, and user detection
- Frontend Integration — JavaScript examples for SPA integration
- Troubleshooting — Common errors and solutions
Testing
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Security Vulnerabilities
If you discover a security vulnerability, please email fengqiyue@gmail.com. Please see SECURITY for more details.
Credits
License
The MIT License (MIT). Please see License File for more information.