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

User Bundle Laravel Package

monofony/user-bundle

Monofony UserBundle integrates user management into Monofony applications: customer and admin user entities, authentication, registration, password reset and profile handling. It builds on Sylius resources and Symfony security to give you a ready-to-extend user system out of the box.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package. It is a read-only subtree split of the UserBundle from the Monofony monorepo, which is itself a rename of Sylius/SyliusUserBundle. If you're coming from Laravel, understand up front: there is no Auth::guard(), no Authenticatable contract, no Hash::make(). Day-to-day work here means writing Doctrine entities, YAML security config, and DI service definitions. You cannot composer require this into a Laravel app without dragging in Symfony Security, the DI container, and Doctrine ORM.

Minimal install (v1.10.0 dropped PHP 7.3 and added PHP 8 — check the constraint before pinning; on 7.3 you are stuck on the previous tag):

composer require monofony/user-bundle
# then read composer.json: does it require sylius/* or monofony/* components, and what are the php/ext constraints?

Register the bundle (find the real class name in the package's composer.json autoload section — it is the Sylius bundle with the namespace swapped):

// config/bundles.php
return [
    Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
    Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
    Sylius\Bundle\ResourceBundle\SyliusResourceBundle::class => ['all' => true],
    Monofony\Bundle\UserBundle\MonofonyUserBundle::class => ['all' => true],
];

Create concrete users by extending the abstract base model shipped by the component fork:

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Monofony\Component\User\Model\User as BaseUser;

/**
 * @ORM\Entity
 * @ORM\Table(name="app_admin_user")
 */
class AdminUser extends BaseUser
{
}

Wire two firewalls/providers in security.yaml (one per user type):

security:
  providers:
    admin: { entity: { class: App\Entity\AdminUser, property: username } }
    shop:  { entity: { class: App\Entity\ShopUser,  property: email } }
  password_hashers:  # security.encoders on Symfony < 5.3
    App\Entity\AdminUser: bcrypt
    App\Entity\ShopUser: bcrypt
  firewalls:
    admin:
      pattern: ^/admin
      provider: admin
      form_login: { login_path: admin_login, check_path: admin_login_check }
      logout: { path: admin_logout }
    shop:
      pattern: ^/
      provider: shop
      form_login: { login_path: shop_login, check_path: shop_login_check }

Where to look first, in this order:

  1. DependencyInjection/Configuration.php — the canonical list of every config key and resource definition.
  2. Resources/config/doctrine/model/User.orm.xml — tells you which fields are mapped as MappedSuperclass and which you must map yourself.
  3. Resources/config/services.xml — the service IDs you will end up decorating (user_manager, password updater, canonicalizers, token generator).
  4. The upstream Sylius UserBundle docs — they apply almost 1:1, and there are years of StackOverflow answers for them; the Monofony fork has none.

First use case: an admin user logging in to /admin via form login, and a shop customer registering and logging in on the storefront, each with a separate provider and separate table. That exercise touches the model, the provider, the password lifecycle, and the security config — the four things you'll customize in every project.

Implementation Patterns

The "multiple users" feature is just multiple concrete classes. There is nothing magic: extend the base User once per persona, give each its own table, repository, and firewall. The base model lives in the component package (Monofony\Component\User\Model\User), not the bundle, so your entities extend that and you register each with SyliusResourceBundle:

sylius_resource:
  resources:
    app.admin_user:
      driver: doctrine/orm
      classes:
        model: App\Entity\AdminUser
        repository: App\Repository\AdminUserRepository
        form: App\Form\AdminUserType
    app.shop_user:
      driver: doctrine/orm
      classes:
        model: App\Entity\ShopUser
        repository: App\Repository\ShopUserRepository

Always create and update users through the manager, never via EntityManager::persist() directly. The manager is what runs the canonicalizers (lowercasing usernameCanonical/emailCanonical), dispatches the password-update step that hashes plainPassword into password, clears the plaintext, and generates the confirmation token. Bypassing it leaves canonical columns null, and your user silently cannot log in.

Password lifecycle is a two-step contract: you set plainPassword on the entity, then persist via the manager. A listener picks up the plaintext, calls the password encoder, and nulls the plaintext. If you're writing tests or fixtures, replicate that by calling the manager — do not hand-set password.

Registration flow is the SyliusResourceBundle pattern, not a custom controller: a resource route with create/store actions, a form type registered in the classes.form slot, and a redirect on success. Customize the form type; don't fork the controller.

Password reset uses the token generator + TTL services. The bundle gives you the token primitives and the token-TTL config; you supply the mailer and the reset form. Hook this up as your own controller that calls the manager's token methods, then a second action that consumes the token and reassigns plainPassword.

OAuth is thin scaffolding, not a solution. Expect model fields like oauthProvider/oauthIdentifier, a repository finder for them, and a form type. The actual OAuth dance is HWIOAuthBundle (or knpuniversity/oauth2-client-bundle) with its own firewall, resource owners, and an oauth_user_provider service you write. The pattern that works:

  1. OAuth firewall authenticates against the external provider.
  2. In loadUserByOAuthUserResponse, look up by (provider, identifier).
  3. If not found, look up by email; if found, link (set the OAuth fields) rather than creating a duplicate.
  4. Otherwise create through the user manager so canonicalization and token generation stay consistent.

Step 3 is where account-takeover bugs live — never auto-link by email unless the provider asserts the email is verified.

Roles. The base model implements Symfony's UserInterface::getRoles(). Whether the roles property is JSON-mapped by the bundle's XML mapping varies between versions — inspect Resources/config/doctrine/model/ before adding a roles column to your entity, or you'll get a duplicate-mapping error. This bundle predates Symfony's Role value objects, so it uses plain string roles like ROLE_ADMIN.

Extension points in order of preference:

  • Redefine classes.model / classes.repository / classes.form in the resource config (supported, upgrade-safe).
  • Override container parameters (*.model.user.class) in config/services.yaml — the Sylius-family convention.
  • Decorate the manager, password updater, or token generator with a Symfony service decorator.
  • Override templates under templates/bundles/<BundleName>/.

Gotchas and Tips

v1.10.0 is a narrow, dependency-level release: PHP 8 allowed, PHP 7.3 dropped. Nothing else changed. No new features, no deprecation removals, no Symfony 6 work, no bug fixes called out. Read it for what it tells you rather than what it ships: it proves the package still builds and still accepts a modern PHP runtime, and it proves the maintenance is a compatibility bump roughly once every few years (previous tag 2021). Pin the exact version, commit your composer.lock, and budget for forking it into your own src/ if you build anything serious. For a new project, the honest recommendation remains Sylius/SyliusUserBundle (actively maintained, same API surface) or Symfony's own make:user — this package's value is as a reference implementation of the Sylius user model, not as a long-lived dependency.

PHP 8 support is not Symfony 6 support. The release note changes the runtime, not the framework integration. Everything below about encoders/password_hashers, getSalt(), and \Serializable still applies unless you verify it in the source for v1.10.0 — a PHP 8 compatibility commit frequently means "it parses and the test suite is green," not "the deprecations are gone."

Do not install it alongside sylius/sylius-user-bundle. Service IDs are namespaced per bundle so the container may survive, but you'll get two sets of Doctrine mappings for near-identical abstract models, duplicate security listeners, and ambiguous autowiring. Pick one.

Config-key guessing wastes an hour. The key is the Sylius one renamed (sylius_user → monofony_user, or whatever the extension alias actually is). Confirm with:

bin/console debug:config <alias>
bin/console debug:container UserManager --show-private
bin/console doctrine:mapping:info         # did your MappedSuperclass actually load?
bin/console debug:firewall admin          # are the provider and authenticator what you think?
bin/console lint:container

doctrine:mapping:info is the one you'll run most — "the class is not a valid entity or mapped superclass" almost always means the bundle's XML mapping isn't being auto-loaded (missing auto_mapping, or a custom mapping config that doesn't include the bundle's Resources/config/doctrine).

Symfony 5.3+ rename. security.encoders became security.password_hashers, and getSalt() was removed from the interface. If the model still implements the old contract, expect deprecation noise at minimum and a fatal on getSalt() at worst. Check the shipped model before you write config against it.

Serializable deprecation. The user model implements \Serializable, which Symfony 5.4+ warns about and Symfony 6 deprecates. The user object is serialized into the session; if you change fields on your concrete class, old sessions will throw on deserialization. Either implement __serialize/__unserialize in your entity or plan session invalidation on deploy.

Double-hashing. The most common bug: setting password manually and letting the listener run, or calling the password updater twice in a registration controller. Symptom: login fails with a correct password, and password in the DB looks like a hash of a hash. Test by dumping the plaintext right before persist.

Canonical fields are the second most common bug. usernameCanonical/emailCanonical are what the provider actually queries. If you import users with raw SQL or Doctrine fixtures, populate them (lowercase) or the provider finds nothing.

OAuth expectations. The description says "OAuth support"; the code says "here are two nullable columns and a finder." Don't scope OAuth as a day of work based on the README. Also note HWIOAuthBundle itself is barely maintained — knpuniversity/oauth2-client-bundle plus a custom authenticator is the more durable path today.

Confirmation tokens expire. There's a TTL config; check it before you assume a "broken" reset link is a bug in your controller. Tokens are one-shot — consuming one must clear it.

Debugging a login that "just doesn't work" in order: (1) debug:firewall to confirm the provider; (2) query the DB for usernameCanonical/emailCanonical/enabled; (3) check whether enabled is false — a fresh entity defaults to disabled in the Sylius model, and a disabled user fails authentication with no useful log line; (4) check the password hash prefix matches the configured hasher.

Treat it as vendored source. One compatibility release after a multi-year gap, a single star, and no dependents is not a revival — it is the minimum required to keep the subtree split installable. The realistic day-to-day posture is still: read the code, copy the model and the manager into your app, and own it. That costs an afternoon and removes the entire class of "abandoned dependency" risk, which remains the dominant consideration here.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle