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

Framework Multi User Bundle Laravel Package

sumocoders/framework-multi-user-bundle

Symfony bundle from SumoCoders that adds multi-user support to the framework, letting you manage multiple user accounts, associate users with shared entities or tenants, and integrate user handling into your application's authentication and admin flows.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle (not Laravel), which explains part of why it is 1 star and archived: it was built for the SumoCoders mini-framework on Symfony 2.x/3.x and FOSUserBundle. If you are coming from Laravel, the closest mental model is "multi-auth / multi-guard": several distinct user entities, each with its own provider, firewall, login form, and user checker, all coordinated by a shared discriminator.

Minimal steps to get it running:

  1. Pull it in (expect platform constraint failures on any modern PHP — this is 2018-era code):
    composer require sumocoders/framework-multi-user-bundle
    
  2. Register the bundle:
    // app/AppKernel.php  (Symfony 2/3 style)
    $bundles = [
        // ...
        new FOS\UserBundle\FOSUserBundle(),
        new SumoCoders\FrameworkMultiUserBundle\FrameworkMultiUserBundle(),
    ];
    
  3. Define your user types in config.yml. This is the file you will live in. Each type points to a concrete entity extending the bundle's base user and to its provider/firewall:
    framework_multi_user:
        user_discriminator: multi_user_discriminator
        users:
            customer:
                class: AppBundle\Entity\Customer
            admin:
                class: AppBundle\Entity\Admin
    
  4. Configure each firewall + provider. The firewall name is what the bundle uses to resolve the user type:
    security:
        providers:
            customer: { id: app.customer_provider }
            admin:    { id: app.admin_provider }
        firewalls:
            customer:
                pattern: ^/customer
                provider: customer
                form_login: { login_path: /customer/login, check_path: /customer/login_check }
                logout: { path: /customer/logout }
            admin:
                pattern: ^/admin
                provider: admin
                form_login: { login_path: /admin/login, check_path: /admin/login_check }
                logout: { path: /admin/logout }
    

Where to look first:

  • DependencyInjection/Configuration.php — the actual shape of the framework_multi_user tree; this is the source of truth, not the README.
  • UserDiscriminator (the request/listener class) — it stores the current user type in the session; nearly every bug traces back to it.
  • Resources/config/services.xml — service ids you can override if you need to change the discriminator.
  • The Entity/ directory for the base user class you must extend.

First use case: two login flows behind two firewalls (e.g. /customer/login and /admin/login), each authenticating a different Doctrine entity, with a shared base user providing roles and password hashing. That is the whole point of the bundle.

Implementation Patterns

One base entity, one concrete per type. Extend the bundle's base user (which itself extends the FOS user) and let the discriminator handle routing between them:

// src/AppBundle/Entity/Admin.php
class Admin extends BaseUser
{
    // admin-specific fields
}

Use Doctrine single-table inheritance on a common parent if you want a shared table, or separate tables with separate repositories if you want clean isolation. The bundle works with either, but shared identity across types is not supported — different firewalls mean different sessions of users.

Discriminator-in-session pattern. The discriminator is set when a login is attempted and read by listeners later in the request cycle. This is the pattern you'll see throughout:

// typically handled for you by the bundle's listener
$discriminator->setUserType('admin');

Provider-per-type. Each user type needs its own provider wired to its own repository. Don't reuse one provider across two firewalls — the bundle resolves the user type from the firewall, and a shared provider makes the resolution ambiguous:

services:
    app.customer_provider:
        class: AppBundle\Security\CustomerProvider
        arguments: ['@doctrine']

User checker per provider. If your entity implements AdvancedUserInterface (locked/expired), configure a user_checker per firewall. This is where per-type business rules (e.g. "customers must be email-verified, admins must exist") belong.

Per-type forms and controllers. Register separate FOSUserBundle form types and copy the standard FOS controllers into your app, one per type. The bundle gives you the plumbing; the controllers are still yours. A common layout:

src/AppBundle/Controller/Customer/{SecurityController,RegistrationController,ProfileController}.php
src/AppBundle/Controller/Admin/{SecurityController,RegistrationController}.php

Integration tips:

  • Keep the two firewalls' route prefixes disjoint (^/admin, ^/customer) — the discriminator derives type from the firewall pattern, so overlapping patterns silently break login.
  • Share view templates but not controllers; the differences (redirect target after login, default ROLE) are per type.
  • If you need cross-type links (e.g. admins editing customers), use role-checking in the admin controller, not the discriminator — do not try to run both users in one session.
  • Put user-type-specific services under a tag-free, explicit id (e.g. app.admin.user_manager) rather than relying on FOSUserBundle's default manager, which assumes one user class.

Gotchas and Tips

This package is archived and last released 2018-11-27. There will be no security patches. Treat it as a reference implementation to copy, not a dependency to run in production. The Symfony ecosystem moved to multi-guard natively long ago; FOSUserBundle itself is deprecated in favour of symfony/security-bundle's user providers. If you are on a modern stack, implement the pattern directly — don't install this.

Modern PHP install failures. The composer constraints target PHP 5.x/7.0-era. You will likely need --ignore-platform-reqs or --no-scripts to even install it. That is a warning sign, not a workaround to standardise.

The discriminator is session-backed. Two failures are extremely common:

  • Logging into /admin while already logged into /customer in the same session can overwrite the discriminator; always logout or verify with a clean session when debugging.
  • If the discriminator is empty, listeners that expect it throw a null-type error. The fix is usually to ensure the login listener ran before your listener in the same request — check app/config/services.yml priority.

Firewall pattern overlap is silent. ^/customer also matches ^/customer/admin if you forgot a more specific firewall. The first firewall in order wins and the discriminator gets the wrong type. Order firewalls most-specific-first.

Doctrine inheritance pitfalls. With single-table inheritance, every query on the parent hydrates all types; if the bundle's provider filters by instanceof, that is fine, but custom DQL that joins the parent will surprise you. Add a discriminatorColumn and keep it stable — changing it later orphans rows.

Provider and user checker must agree. A user checker for customer running on the admin firewall produces "account is locked" failures for perfectly valid admins. Audit security.firewalls.*.user_checker line by line.

Debugging login loops. The chain is: firewall → provider → loadUserByUsername → user checker → discriminator. If you get a redirect back to the login form with no error, check security.access_control first (often a missing IS_AUTHENTICATED_ANONYMOUSLY on login_check), then the user checker. Turn on monolog at DEBUG for security and request channels.

Extension points (the only graceful ones):

  • Override the UserDiscriminator service definition to change how the type is detected (e.g. from a request attribute rather than session).
  • Override the base user entity and its getRoles() to change role semantics.
  • Do not fork the bundle to add a third user type "properly" — configuration already supports N types; keep the fork clean.

If you are on Laravel, there is no port and you don't want one. The idiomatic equivalents are multiple guards in config/auth.php + Auth::guard('admin')->attempt(...), a shared parent user model or separate models, and middleware per guard. Copy the architectural idea (provider-per-user-type, separate login routes, per-type user checks) and leave the Symfony bundle behind.

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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager