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

nucleos/user-bundle

NucleosUserBundle is a Symfony bundle for complete user management: registration, login, password reset, profile editing, and account administration. It integrates with Symfony Security and Doctrine, offering flexible events, templates, and configuration for adding secure user accounts to Symfony ap...

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package — there is no service provider, no facade, no config/nucleos_user.php. If you are in a Laravel codebase, stop here; the equivalent job is done by laravel/ui/breeze/fortify. Everything below assumes you are in (or are evaluating) a Symfony app. Translate your instincts roughly like this:

Laravel NucleosUserBundle / Symfony
Illuminate\Foundation\Auth\User Nucleos\UserBundle\Model\User (mapped superclass you extend)
Authenticatable contract Nucleos\UserBundle\Model\UserInterface
Hash::make() on save Nucleos\UserBundle\Util\PasswordUpdater inside UserManager::updateUser()
Auth::routes() The bundle's routing/*.xml route sets
php artisan make:auth Form types + controllers shipped in the bundle
Eloquent observers NucleosUserEvents::* event listeners

Minimum viable install (15 minutes):

composer require nucleos/user-bundle:^4.1

You need PHP 8.2+, Symfony 7 or 8, Doctrine ORM/ODM, symfony/mailer and symfony/twig-bridge (both required for the shipped email flows). On Symfony 8, ^4.1 is the first line that will resolve.

// config/bundles.php
Nucleos\UserBundle\NucleosUserBundle::class => ['all' => true],

Then, in order, before writing any code:

  1. bin/console config:dump-reference nucleos_user — do this first. The bundle's docs trail the code; the dumped reference is the authoritative list of keys (db_driver, firewall_name, user_class, from_email, registration, resetting, profile, change_password, service, group).
  2. bin/console debug:container nucleos_user and bin/console debug:router | grep nucleos — confirm service IDs and routes in your version rather than trusting blog posts.
  3. Create your entity extending the base and map only the ID:
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Nucleos\UserBundle\Model\User as BaseUser;

#[ORM\Entity]
#[ORM\Table(name: 'app_user')]
class User extends BaseUser
{
    #[ORM\Id, ORM\Column, ORM\GeneratedValue]
    protected ?int $id = null;
}
  1. Wire it up:
# config/packages/nucleos_user.yaml
nucleos_user:
    db_driver: orm
    firewall_name: main
    user_class: App\Entity\User
    from_email: { address: [email protected], sender_name: Acme }
# config/routes/nucleos_user.yaml  (granular imports beat all.xml)
nucleos_user_security:  { resource: "@NucleosUserBundle/Resources/config/routing/security.xml" }
nucleos_user_registration: { resource: "@NucleosUserBundle/Resources/config/routing/registration.xml", prefix: /register }
nucleos_user_resetting: { resource: "@NucleosUserBundle/Resources/config/routing/resetting.xml", prefix: /resetting }
nucleos_user_profile:   { resource: "@NucleosUserBundle/Resources/config/routing/profile.xml", prefix: /profile }
  1. Point security.yaml at the bundle's user provider (id: the service you found in step 2) and add password_hashers: { Nucleos\UserBundle\Model\User: auto }. Run bin/console doctrine:schema:update --dump-sql and eyeball it before executing.

First use case to validate end-to-end: registration → confirmation email → login → profile edit → password reset. If all five work, the rest is your domain logic.

Implementation Patterns

Consume the pieces, not the whole bundle. The value here is UserManager, the form types, and the mailer — not the opinions. You can import only resetting.xml routes and build your own registration as a JSON API:

final class RegisterAction
{
    public function __construct(
        private UserManagerInterface $userManager,
        private EntityManagerInterface $em,
    ) {}

    public function __invoke(Request $r): Response
    {
        $user = $this->userManager->createUser();
        $user->setUsername($r->request->get('username'))
             ->setEmail($r->request->get('email'))
             ->setPlainPassword($r->request->get('password'))   // never setPassword()
             ->setEnabled(true);

        $this->userManager->updateUser($user);   // hashes, canonicalizes, persists, flushes
        return new JsonResponse(['id' => $user->getId()], 201);
    }
}

updateUser() is the whole point of the abstraction: it runs CanonicalFieldsUpdater (lowercases username/email), PasswordUpdater (only if plainPassword is set), then persists + flushes. Bypassing it with raw $em->persist() is the #1 cause of "my password is stored in plaintext" and "duplicate emails allowed" bugs.

Hook domain logic via events, not by overriding controllers. Subscribe to NucleosUserEvents::REGISTRATION_CONFIRMED, REGISTRATION_COMPLETED, RESETTING_RESET_COMPLETED, CHANGE_PASSWORD_COMPLETED, PROFILE_EDIT_COMPLETED, SECURITY_IMPLICIT_LOGIN. Typical uses: provisioning a tenant, sending a welcome mail, auditing password changes, adding a new user to a default group.

#[AsEventListener(NucleosUserEvents::REGISTRATION_CONFIRMED)]
final class ProvisionWorkspaceListener { /* ... */ }

Customize forms by decoration, not by editing vendor. Register your own form type extending the bundle's (RegistrationFormType, ProfileFormType, ChangePasswordFormType, ResettingFormType) and point the config key for that form at your class. Same trick for controllers: implement the same route with #[Route] on your own controller and don't import the corresponding *.xml.

Seed and test deterministically. Use UserManager::createUser() in DataFixtures (Alice bundles included) rather than instantiating the entity directly — you get canonicalization for free. For functional tests, createClient() + submitForm() against the bundle routes is the fastest smoke test; the confirmation token is on the entity, so you can build confirmation URLs without reading mail.

Integrate, don't extend, for anything modern. The bundle deliberately has no 2FA, no OAuth, no admin UI, no JWT. Pair it with scheb/2fa-bundle, knpuniversity/oauth2-client-bundle, lexik/jwt-authentication-bundle. Because it is just a UserProvider + entity, these compose cleanly.

Gotchas and Tips

  • You are reading FOSUserBundle docs. NucleosUserBundle is a maintained fork of FOSUserBundle, which is a fork of Symfony's old UserBundle. Service IDs are renamed (fos_user.* → nucleos_user.*), salt was removed, and Swiftmailer was replaced by Symfony Mailer. Any tutorial that mentions $user->setSalt() or fos_user.mailer.twig_swift is stale; you'll get "no such column: salt" or a container error. Trust config:dump-reference over Google.
  • firewall_name must exactly match a firewall key. A typo doesn't throw at boot — it silently breaks logout redirects and session invalidation in ways that take hours to find.
  • Set plainPassword, never password. And null out plainPassword after updateUser() if you keep the entity managed across requests (e.g., in a message handler), or you risk re-hashing a stale value.
  • Nullable columns matter. confirmation_token, password_requested_at, last_login must be nullable; the schema tool sometimes guesses wrong on inherited mappings. Always --dump-sql first.
  • Resolve target entities. If you support both ORM and ODM, or use UserInterface/GroupInterface type-hints in relations, add doctrine.orm.resolve_target_entities mappings — otherwise Doctrine throws "target entity not found" at schema time.
  • Email templates are not automatic. Configure resetting.email.template and registration.confirmation.template, and override the shipped Twig under templates/bundles/NucleosUserBundle/. If mail is silently not sent, check the service.mailer config and that both symfony/mailer and symfony/twig-bridge are installed.
  • Token TTL and single-use semantics live in resetting.token_ttl (default 86400s). Tokens are cleared on successful reset — if you build your own reset endpoint, call setConfirmationToken(null) yourself.
  • Extension points, ranked by cost: event listeners → config keys → custom form types → decorating UserManager → overriding controllers → forking. If you need the last two, consider whether symfony/security + make:user is the better fit — it is the Symfony-recommended default and has no fork lineage.
  • Debugging checklist: debug:container nucleos_user.user_manager (exists?), debug:router (routes imported?), debug:event-dispatcher | grep Nucleos (listeners registered?), doctrine:mapping:info (entity recognized?). Most issues are one of these four.
  • Version pin deliberately — and re-check that pin. The 4.x line is current and, as of 4.1.0 (April 2026), explicitly supports Symfony 8 and doctrine/collections 3, so ^4.1 is the right constraint for any new Symfony 7/8 app. 4.1.0 is a pure compatibility release: no new config keys, no renamed services, no deprecations, so upgrading from 4.0.x is a composer update with nothing to change in your code. Two footnotes: paragonie/random_compat was dropped from the dependency tree (nothing to do unless you were relying on it transitively — the bundle uses random_bytes), and the PHPUnit 13 bump is dev-only. If you are stuck on an older Symfony, pin the matching major and expect the salt-era API. With ~61 stars and effectively zero dependents, you are close to the maintainers — open issues with a reproducer rather than assuming a Stack Overflow answer exists.

Honest verdict for a Laravel-oriented team: adopt only if you're already in Symfony and want prebuilt registration/reset/profile controllers. The bundle is small, clean, and MIT, and 4.1.0 is a good signal — an actively released fork that already tracks Symfony 8 rather than a dormant one — but it remains a compatibility fork with a narrow audience. Budget time to read vendor/nucleos/user-bundle/src and its DependencyInjection/Configuration.php, because that source will answer 90% of your questions faster than the docs.

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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect