prayno/casauth-bundle
CASAuth Bundle adds Central Authentication Service (CAS) single sign-on to PHP applications, with CAS login and logout, user authentication, and session handling for institutions that rely on CAS servers. It simplifies connecting apps to existing CAS identity providers.
Despite the "Bundle" suffix, prayno/casauth-bundle is a Symfony package — it will not composer require cleanly into a Laravel app and has no service provider, no config file publish, and no facade. Treat it as a reference implementation, not a drop-in dependency.
Release 1.4 changes nothing about that picture: it is a Symfony 5 compatibility fix ("without breaking SF < 4.2"). No Laravel-facing surface was added, so the conclusion below is unchanged.
What to read first, in this order:
composer.json — confirm the phpCAS dependency (typically apereo/phpcas). That library is what actually talks to your CAS server; the bundle is a thin Symfony wrapper around it.DependencyInjection/Configuration.php — this is the single most useful file for a Laravel developer. It enumerates every cas_* config key (host, port, context, certificate path, validation mode, version). Copy these as your config/cas.php.Security/CasAuthenticator.php (or Security/Authentication/Provider/CasProvider.php on older branches) — the login flow: redirect → ticket → validate → user.Security/CasUserProvider.php — how a CAS attribute (e.g. mail, uid) is mapped to a local user.First real use case in Laravel: CAS-backed SSO against an Apereo CAS server (typical university/enterprise SSO). You will end up doing one of:
phpCAS directly in a custom Illuminate\Contracts\Auth\Guard plus a cas.login / cas.callback route pair, orcas_* config shape and user-provider attribute mapping.Either way, spend 30 minutes in Configuration.php and CasAuthenticator.php before writing a line — they save you a day of phpCAS trial-and-error.
The guard pattern. The bundle's flow maps cleanly onto a Laravel custom guard:
// app/Auth/CasGuard.php
public function user()
{
if ($this->user) return $this->user;
if ($uid = session('cas_uid')) {
return $this->user = $this->provider->retrieveById($uid);
}
return null;
}
public function check() { return !is_null($this->user()); }
public function attempt(array $credentials = [], $remember = false)
{
\phpCAS::forceAuthentication(); // redirects on first hit
$uid = \phpCAS::getUser();
$attrs = \phpCAS::getAttributes();
$user = $this->provider->retrieveByCredentials(['email' => $attrs['mail']])
?? $this->provider->createFromCas($uid, $attrs);
$this->login($user);
return true;
}
Register it via Auth::extend('cas', ...) in a CasAuthServiceProvider.
Config-first bootstrapping. Mirror the bundle's config keys 1:1 so ops documentation transfers:
// config/cas.php
return [
'host' => env('CAS_HOST'),
'port' => env('CAS_PORT', 443),
'context' => env('CAS_CONTEXT', '/cas'),
'certificate' => env('CAS_CERT_PATH', storage_path('cas/ca.pem')),
'validate' => env('CAS_VALIDATE', 'ca'), // 'ca' | 'none'
'version' => env('CAS_VERSION', '2.0'),
'logout_redirect' => env('CAS_LOGOUT_URL'),
];
Bootstrap phpCAS early. phpCAS is a global-state library — it is not PSR-4 friendly. Initialise it in a middleware or service provider before the guard runs, once per request, guarded by a static flag:
if (!\phpCAS::isInitialized()) {
\phpCAS::client(CAS_VERSION_2_0, config('cas.host'), config('cas.port'), config('cas.context'));
config('cas.validate') === 'ca'
? \phpCAS::setCasServerCACert(config('cas.certificate'))
: \phpCAS::setNoCasServerValidation();
}
Route shape. Two routes is the standard: GET /auth/cas calls forceAuthentication() (redirects out), and the CAS server returns to the same URL with ?ticket=…, which phpCAS consumes on the next call. A single route handles both — that's the pattern the bundle uses.
Logout. phpCAS::logout() on the Laravel side, then redirect back to the bundle's logout_redirect equivalent so the CAS session terminates too. Local Auth::logout() alone leaves the CAS session alive and re-authenticates the user on the next request.
User provisioner. Keep a dedicated CasUserProvisioner — CAS attribute names vary by deployment (uid, sAMAccountName, mail, eduPersonPrincipalName). Centralise the lookup so you can swap it per-environment without touching the guard.
composer install shortcut, no php artisan vendor:publish. If you composer require prayno/casauth-bundle you will pull Symfony dependencies into your app for no functional gain. Vendor the two or three files you need, or just use apereo/phpcas directly. Release 1.4 does not change this — it only adjusts Symfony's DI/security wiring.phpCAS itself is more actively maintained; pin a recent apereo/phpcas rather than whatever the bundle pinned.$_SESSION before Laravel has booted its session store in some configurations. If you see "session already started" or lost auth state, either disable phpCAS's session handling (\phpCAS::setSessionHandler(...) with a null handler) or bootstrap the CAS guard in a middleware that runs after StartSession.forceAuthentication() / getUser() twice for the same ?ticket= — the second call will fail. Cache phpCAS::getUser() in the session immediately after validation, exactly as the bundle's authenticator does.setNoCasServerValidation(); staging/prod must point at the CA's PEM. The bundle's cas_certificate_path key maps to setCasServerCACert() — missing or expired certs surface as opaque "CAS authentication failed" errors with no useful message. Log phpCAS::getServerServiceValidateURL() response bodies when debugging.?ticket= from the URL. After successful validation, redirect to the clean URL so refresh doesn't replay the ticket and fail. This is easy to forget and produces intermittent login failures.$request->session()->regenerate() immediately after Auth::login($user). The Symfony authenticator does this implicitly via TokenInterface; you must do it explicitly in Laravel.CasClient interface (methods: isAuthenticated, getUser, getAttributes, forceAuthentication, logout) with a real implementation delegating to \phpCAS and a fake for tests. Without this, your guard is untestable.CasAuthenticator; copy the logic.apereo/phpcas minor — the legacy constraints may still resolve to a phpCAS with API drift from what the code expects, and the 1.4 patch says nothing about relaxing them.How can I help you explore Laravel packages today?