apereo/phpcas
Apereo PHP CAS is a PHP client library for Central Authentication Service (CAS) single sign-on. It handles CAS login/logout flows, ticket validation, session management, and proxy support, with configurable endpoints for integrating CAS authentication into PHP apps.
Installation
composer require apereo/phpcas
Register the service provider in config/app.php:
'providers' => [
// ...
Apereo\Cas\Client\Provider\Laravel\CasServiceProvider::class,
],
Configuration Publish the config file:
php artisan vendor:publish --provider="Apereo\Cas\Client\Provider\Laravel\CasServiceProvider"
Update config/cas.php with your CAS server details (e.g., URL, service validation URL).
First Use Case: Authenticate a User Add middleware to protect routes:
Route::middleware(['cas'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
});
The middleware (CasMiddleware) will handle CAS authentication automatically.
Login Redirect
Use CasAuthenticator to redirect users to CAS:
use Apereo\Cas\Client\Provider\Laravel\CasAuthenticator;
$authenticator = new CasAuthenticator(config('cas'));
return redirect()->to($authenticator->getLoginUrl());
Callback Handling
The middleware (CasMiddleware) processes the CAS callback (/cas/callback) and validates the ticket. On success, it logs the user in using Laravel’s Auth::login().
Service Validation
Ensure your CAS server’s service URL is whitelisted in config/cas.php:
'service' => [
'url' => 'https://your-app.com/cas/callback',
],
Fetch User Attributes After successful authentication, retrieve CAS attributes:
$attributes = $request->session()->get('cas.attributes');
$user = User::updateOrCreate(
['email' => $attributes['email']],
['name' => $attributes['givenName'] ?? '']
);
Custom Attribute Mapping
Extend CasUserProvider to map CAS attributes to Laravel users:
class CustomCasUserProvider extends CasUserProvider {
protected function mapAttributes($attributes) {
return [
'email' => $attributes['eduPersonPrincipalName'],
'roles' => $attributes['roles'] ?? [],
];
}
}
Bind it in CasServiceProvider:
$this->app->bind(CasUserProvider::class, CustomCasUserProvider::class);
$authenticator = new CasAuthenticator(config('cas'));
return redirect()->to($authenticator->getLogoutUrl());
Route::get('/logout', function () {
Auth::logout();
return redirect('/');
});
CasClient directly in tests:
$client = new CasClient(config('cas'));
$ticket = $client->validateServiceTicket('ST-123');
$this->assertTrue($ticket->isValid());
Ticket Validation Failures
service URL in config/cas.php matches the callback URL exactly (including http/https).$client = new CasClient(config('cas'));
$ticket = $client->validateServiceTicket($request->ticket);
if (!$ticket->isValid()) {
Log::error('CAS validation failed:', $ticket->getException());
}
Session Expiry
$ticket = $request->session()->get('cas.ticket');
if ($ticket && !$client->validateServiceTicket($ticket)->isValid()) {
return redirect()->route('cas.login');
}
Attribute Parsing
$attributes = json_decode(json_encode($attributes), true);
Enable Verbose Logging
Configure config/cas.php:
'debug' => env('CAS_DEBUG', false),
Check logs for CAS client errors.
Inspect Raw Responses
Use CasClient directly to debug:
$response = $client->getServiceTicketValidator()->validate($ticket);
dd($response->getAttributes());
Custom Authentication Guard Extend Laravel’s guard to use CAS:
class CasGuard extends Guard {
public function user() {
if (!$this->hasUser()) {
$this->setUser($this->createUserFromCas());
}
return parent::user();
}
}
Proxy Authentication
For reverse proxy setups, configure CasClient to trust proxy headers:
$client = new CasClient(config('cas'));
$client->setProxy(true);
Multi-CAS Server Support Dynamically switch CAS servers based on tenant:
$casConfig = config("cas.tenants.{$tenant}");
$client = new CasClient($casConfig);
Cache Ticket Validation Cache validated tickets for short-lived sessions:
$ticket = Cache::remember("cas.ticket.{$ticket}", now()->addMinutes(5), function () use ($client, $ticket) {
return $client->validateServiceTicket($ticket);
});
Lazy-Load Attributes Avoid fetching all attributes upfront:
$client->getServiceTicketValidator()->setAttributeFilter(['email', 'givenName']);
How can I help you explore Laravel packages today?