Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Uid User Bundle Laravel Package

l3/uid-user-bundle

A Symfony bundle for UID-based user management, providing user entities, authentication integration, and account handling for applications that identify users by unique ID. Lightweight and easy to wire into existing Symfony projects.

View on GitHub
Deep Wiki
Context7

Getting Started

Know what you're installing first. l3/uid-user-bundle is a Symfony bundle, not a Laravel package. It plugs into Symfony's Security component as a user provider that authenticates against a CAS server and returns only the UID — no email, no display name, no roles. If you're in a Laravel codebase, you cannot composer require this and expect a service provider to register itself. Your realistic options are:

  1. Port the idea, not the code. CAS is just a redirect + ticket validation handshake (/login?service=... → ?ticket=ST-... → POST /serviceValidate → <cas:user>). That's ~80 lines with Laravel's HTTP client and a guard. This is almost always the right call given the package's state.
  2. Run it beside Laravel in a small Symfony app that issues a signed token/SAML assertion Laravel consumes.
  3. Fork and extract the CAS client class into a Laravel guard.

Minimal first steps if you're committing to it (Symfony context):

composer require l3/uid-user-bundle
// config/bundles.php
return [
    // ...
    L3\UidUserBundle\UidUserBundle::class => ['all' => true],
];
# config/packages/security.yaml
security:
    providers:
        cas:
            id: <the bundle's user provider service id>  # check the bundle's services.yaml
    firewalls:
        main:
            provider: cas
            custom_authenticator: <the bundle's authenticator service id>
            # or the bundle's factory/guard config, depending on version

Where to look first: the bundle's Resources/config/services.yaml (or config/services.yaml in newer layouts) to learn the exact service IDs, and the constructor signature of the user provider — that's where the CAS host, port, path, and validation URL live.

First use case: an internal tool where every employee already has a CAS identity and you don't want to store passwords. You log in, you get jdoe, and you own the rest of the user record.

Honest caveat: 0 stars, 0 dependents, no recognized license (NOASSERTION — check LICENSE in the repo before commercial use), last release Dec 2023. Treat this as a reference implementation, not infrastructure.

Implementation Patterns

The UID-only contract is the whole design

The provider returns a user object with a username and effectively nothing else. Everything downstream is your problem. Plan for it up front:

// Pattern: hydrate-on-login. The CAS UID is a key, not a profile.
final class CasUserProvider implements UserProviderInterface
{
    public function loadUserByIdentifier(string $uid): UserInterface
    {
        $local = User::where('cas_uid', $uid)->first();

        // First login: create a shell record so FKs work immediately.
        $local ??= User::create([
            'cas_uid'  => $uid,
            'name'     => $uid,        // placeholder, enriched later
            'email'    => null,
        ]);

        return new CasUser($local);
    }
}

Always persist a local row keyed on the UID. If you return a transient user object every request, every foreign key in your app breaks and you lose per-user settings.

Enrichment belongs after authentication, not inside it

CAS won't give you a name or email. Don't try to make the provider do it — a slow LDAP lookup inside loadUserByIdentifier runs on every request. Instead:

  • Login-time enrichment: a listener on the security login event, or a queued job, that pulls LDAP/HR data by UID and fills the local row.
  • Stale-tolerant reads: a ProfileSync job that refreshes on a TTL (e.g. nightly) so a renamed employee propagates.

Use the UID as the join key to whatever directory you actually have (LDAP uid, Active Directory sAMAccountName, HR system employee ID). The bundle's job is just to prove identity.

Roles come from your side

Since the bundle returns no roles, the getRoles() on your user object must be computed locally — from groups, a role_assignments table, or an LDAP memberOf sync. Never trust a role delivered over the CAS response without a signature you've verified.

Laravel-shaped equivalent (the port)

If you port, the guard is small and testable:

final class CasGuard
{
    public function __invoke(Request $request)
    {
        if ($request->missing('ticket')) {
            return redirect(config('cas.url') . '/login?service=' . urlencode($request->fullUrl()));
        }

        $xml = Http::asForm()->get(config('cas.url') . '/serviceValidate', [
            'service' => urlencode($request->url()),
            'ticket'  => $request->query('ticket'),
        ]);

        $uid = Str::between($xml->body(), '<cas:user>', '</cas:user>');
        abort_unless($uid !== '', 401);

        Auth::login($this->users->findOrCreateByUid(trim($uid)));

        return redirect()->intended('/');
    }
}

Then Route::get('/auth/cas', CasGuard::class) and guard it with auth. This is a half-day of work and you keep full control of validation, XML parsing, and error handling — which the bundle gives you no visibility into at this level of maturity.

Integration tip: single sign-out

CAS logout is a redirect to /logout?service=..., not a local session destroy. If you're building against this bundle, expect to add a route that flushes the session and then bounces to the CAS logout endpoint. The bundle likely handles only the login half.

Gotchas and Tips

  • License is NOASSERTION. Open the repo's LICENSE/composer.json before it touches a paid product. "No declared license" legally means all rights reserved in most jurisdictions. This is the single biggest blocker, ahead of code quality.
  • It's a Symfony bundle. In a Laravel app, the DependencyInjection extension, tag-based compiler passes, and security.yaml config do nothing. Do not waste time trying to make Illuminate\Foundation boot it.
  • Zero dependents, zero stars, one release. There is no community to answer questions and no downstream code to crib integration snippets from. Read the source; it's small.
  • "Returns only the UID" is a feature, not a limitation — but it means the bundle cannot render a username in your UI, cannot send email, and cannot do authorization. Budget time for a local user table and a profile sync from day one. Retrofitting this later means a data migration.
  • Session fixation and ticket replay. When you port or wrap, call the equivalent of Symfony's session->migrate() / Laravel's session()->regenerate() immediately after a successful serviceValidate, and never accept a ticket twice. A cas:user string from an unvalidated response is trivially forgeable.
  • Validate the XML properly. Regexing <cas:user> out of a response is the classic shortcut and a classic SSRF/injection footgun if you ever point cas.url at anything user-influenced. Use DOMDocument with LIBXML_NONET and check cas:authenticationSuccess before reading the user node.
  • Debugging: CAS failures are opaque by design. Log the raw serviceValidate body at debug level (redact the ticket), and confirm your service parameter matches the registered URL character for character — a trailing slash mismatch is the #1 cause of "invalid ticket" with a valid ticket.
  • Proxy chain: if your app is behind a load balancer, the service URL Laravel/Symfony generates will be http:// and CAS will reject it. Force https in the URL generator or you'll chase this for hours.
  • Extension point worth using if you keep Symfony: the user provider is a single service — decorate it rather than edit it. A class CasUserProviderDecorator implements UserProviderInterface that wraps the bundle's provider and adds local lookup survives composer update and gives you a clean seam to drop the bundle later.
  • Set a deprecation tripwire. Given the 2023 last release, add a test that asserts your auth flow works against a stub CAS, so a PHP minor bump breaking the bundle surfaces in CI rather than in prod.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package