jasig/phpcas
phpCAS is a PHP client library for CAS (Central Authentication Service). It helps PHP apps authenticate users via a CAS server, handling login/logout redirects, validating tickets, and managing sessions with configurable SSL and server settings.
Installation:
composer require jasig/phpcas
Ensure your project uses PHP 8.0+ (recommended) and OpenSSL.
Basic Configuration:
Create a config/cas.php file (or publish defaults via phpcas:publish):
return [
'client' => [
'casServerUrl' => 'https://your-cas-server.com/cas',
'validateUrl' => 'https://your-cas-server.com/cas/validate',
'serviceUrl' => 'https://your-app.com/cas-callback',
'authenticateUrl' => 'https://your-cas-server.com/cas/login',
],
'debug' => env('APP_DEBUG', false),
];
First Use Case: Redirect to CAS login in a Laravel controller:
use Jasig\phpCAS\CasClient;
public function login()
{
$cas = new CasClient();
$cas->setNoCasServerValidation();
$cas->forceAuthentication();
return redirect($cas->getAuthenticationUrl());
}
Verify Authentication:
public function callback()
{
$cas = new CasClient();
if ($cas->validateAuthentication()) {
$user = $cas->getAttributes();
auth()->loginUsingId($user['uid'][0]); // Customize based on CAS attributes
return redirect()->intended('/dashboard');
}
return redirect()->route('login');
}
$cas = new CasClient();
$cas->forceAuthentication(); // Redirects if not authenticated
if ($cas->validateAuthentication()) {
$attributes = $cas->getAttributes();
$user = User::firstOrCreate(
['email' => $attributes['email'][0]],
['name' => $attributes['displayName'][0] ?? null]
);
auth()->login($user);
}
$attributes = $cas->getAttributes();
// Example: $attributes['eduPersonAffiliation'][0] for institutional roles
CasClient to transform attributes:
class CustomCasClient extends \Jasig\phpCAS\CasClient {
public function getUserData() {
$attrs = parent::getAttributes();
return [
'id' => $attrs['uid'][0],
'roles' => $attrs['eduPersonAffiliation'] ?? [],
];
}
}
$cas = new CasClient();
$cas->setProxyValidation(true);
$cas->setProxyCallbackUrl('https://your-api.com/cas-proxy-callback');
Create a HandleCasAuthentication middleware:
public function handle($request, Closure $next) {
$cas = new CasClient();
if (!$cas->isAuthenticated()) {
return redirect()->route('cas.login');
}
return $next($request);
}
Register in app/Http/Kernel.php:
protected $routeMiddleware = [
'cas.auth' => \App\Http\Middleware\HandleCasAuthentication::class,
];
CasClient in AppServiceProvider:
$this->app->singleton(CasClient::class, function () {
$cas = new CasClient();
$cas->setConfig(config('cas.client'));
return $cas;
});
Route::middleware(['cas.auth'])->group(function () {
// Protected routes
});
Store CAS attributes in the session or user model:
session(['cas_attributes' => $cas->getAttributes()]);
// Or attach to user model:
$user->cas_attributes = $cas->getAttributes();
$user->save();
Enable debug mode in config/cas.php:
'debug' => true,
Logs will appear in storage/logs/laravel.log.
SSL certificate problem: self-signed certificate.
$cas->setNoCasServerValidation();
$cas->setCACertPath('/path/to/ca-bundle.crt');
Invalid service URL or SERVICE_VERIFIER failures.
serviceUrl in config matches the exact callback URL (including https/http and trailing slash).$cas->getServiceUrl() to verify the generated URL.Undefined array key when accessing attributes.
$email = $cas->getAttributes()['email'][0] ?? null;
dd($cas->getAttributes());
if ($cas->validateAuthentication()) {
$request->session()->regenerate();
}
PROXY_GRANTING_TICKET failures.
proxyCallbackUrl is set and accessible:
$cas->setProxyCallbackUrl('https://your-app.com/cas-proxy-callback');
$cas->setDebug(true);
$cas->setVerbose(true);
Logs will show raw CAS protocol exchanges.
INVALID_SERVICEINVALID_TICKETINTERNAL_ERRORcurlManually test CAS endpoints:
curl --location 'https://your-cas-server.com/cas/validate' \
--header 'REMOTE_USER: testuser' \
--data-urlencode 'service=https://your-app.com/cas-callback'
Extend CasClient to add pre/post-auth hooks:
class ExtendedCasClient extends \Jasig\phpCAS\CasClient {
public function validateAuthentication() {
$result = parent::validateAuthentication();
if ($result) {
$this->postAuthHook();
}
return $result;
}
protected function postAuthHook() {
// Custom logic (e.g., log auth, update user)
}
}
Filter sensitive attributes before storing:
protected function sanitizeAttributes(array $attrs): array {
unset($attrs['sensitiveAttribute']);
return $attrs;
}
Use a factory pattern to switch CAS servers dynamically:
class CasFactory {
public static function create(string $serverConfig): CasClient {
$cas = new CasClient();
$cas->setCasServer($serverConfig['casServerUrl']);
$cas->setValidateServer($serverConfig['validateUrl']);
return $cas;
}
}
Trigger events for CAS auth lifecycle:
// In your callback controller:
event(new CasAuthenticated($cas->getAttributes()));
Listen in EventServiceProvider:
protected $listen = [
CasAuthenticated::class => [
\App\Listeners\LogCasAuth::class,
],
];
How can I help you explore Laravel packages today?