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

Auto Login Bundle Laravel Package

jmikola/auto-login-bundle

A Symfony bundle that enables passwordless automatic login using secure tokens, letting users authenticate via specially crafted URLs. Integrates with Symfony’s security system for seamless sign-in from emails, links, or trusted applications.

View on GitHub
Deep Wiki
Context7

Getting Started

What it does: adds an auto_login firewall listener that looks for a signed token in a query parameter (autologin by default). If the token verifies, the user is loaded through the firewall's user provider and authenticated for that request — perfect for newsletter links, magic links, one-click unsubscribe/preferences, etc.

Reality check before you commit: the bundle is a thin integration layer over Symfony's legacy security factory system (SecurityFactoryInterface, security.authentication.factory). It works cleanly on Symfony 3.4/4.4, will emit deprecations on 5.3/5.4, and will not load on Symfony 6.x. If you are on 5.3+, use the built-in login_link firewall + LoginLinkHandlerInterface instead — it is the supported successor to this bundle. Pick this package only if you're pinned to an older Symfony.

Install and wire up:

composer require jmikola/auto-login-bundle
// config/bundles.php
Jmikola\AutoLoginBundle\JmikolaAutoLoginBundle::class => ['all' => true],
# config/packages/jmikola_auto_login.yaml
jmikola_auto_login:
    user_identifier: email   # property the token carries / provider looks up by
    # lifetime: 86400         # optional token expiry, in seconds
# config/packages/security.yaml
security:
    providers:
        users:
            entity:
                class: App\Entity\User
                property: email          # MUST match user_identifier above
    firewalls:
        main:
            pattern: ^/
            provider: users
            auto_login: true
            form_login:
                login_path: app_login
                check_path: app_login
            logout: ~

First use case — generate a link anywhere you can inject the token generator:

use Jmikola\AutoLoginBundle\Security\TokenGeneratorInterface;

public function __construct(
    private TokenGeneratorInterface $tokenGenerator,
    private UrlGeneratorInterface $urls,
) {}

public function buildLink(User $user): string
{
    return $this->urls->generate(
        'app_dashboard',
        ['autologin' => $this->tokenGenerator->generate($user)],
        UrlGeneratorInterface::ABSOLUTE_URL,
    );
}

Service ID is jmikola_auto_login.token_generator; it was written in the days of $container->get(), so if you're on Symfony 4.4+ it is likely private — inject it (or add a public alias) rather than calling $this->get().

Implementation Patterns

Batch link generation in a console command. This is the canonical usage: a command loads the audience, builds a link per user, and queues an email. Configure the router's request context first or you'll get http://localhost/... URLs:

// config/packages/test|prod — or set at runtime in the command
// $this->urls->getContext()->setHost('example.com')->setScheme('https');
foreach ($this->users->findNewsletterSubscribers() as $user) {
    $mailer->send($this->buildLink($user), $user);
}

Always land on a "consume and redirect" route. Put the token on a dedicated route, then redirect to a clean URL so the token drops out of the address bar, referrer headers, and analytics:

#[Route('/welcome', name: 'app_autologin_landing')]
public function landing(): Response
{
    // auto_login has already authenticated the request by this point
    return $this->redirectToRoute('app_dashboard');
}

Make that route the only place the token is expected, and set Referrer-Policy: no-referrer (or strict-origin-when-cross-origin) globally.

Scope the token to a purpose. The stock token just proves "this is user X" — it grants a full session. If you use these links for unsubscribe or preference centers, don't rely on the resulting login alone; either (a) build a custom token generator that embeds a purpose/context and check it in the landing controller, or (b) keep the landing controller the sole consumer and never expose authenticated app routes from that request.

Custom token generator. Override jmikola_auto_login.token_generator (alias it to your class) implementing the bundle's TokenGeneratorInterface. Typical reasons: appending a payload (user id + campaign id), versioning the secret, or moving to HMAC-SHA256 with a per-user pepper. Keep the same contract so the listener keeps working.

Defence in depth on top of the login. The listener only authenticates; it says nothing about authorization. Guard the destination with access_control / is_granted() exactly as you would for form login, and keep the auto-login firewall's provider restricted to verified users.

Migrating later. When you move to Symfony 5.3+, port the pattern to:

main:
    login_link:
        check_route: login_check
        signature_properties: [id, password]

with LoginLinkHandlerInterface::createLoginLink(). It is single-use, expiring, and maintained — a strict upgrade.

Gotchas and Tips

  • Symfony version ceiling. auto_login: true only resolves if SecurityFactoryInterface exists. On 6.x you get "Unrecognized firewall option" / bundle load failures. Don't adopt this for new work.
  • user_identifier must match the provider's lookup property. If it's email but your entity provider uses username, the listener queries by the wrong field and authentication silently fails (or throws UsernameNotFoundException). Align jmikola_auto_login.user_identifier with security.providers.*.entity.property.
  • Tokens are deterministic, not single-use. Without lifetime, a generated token is stable for that user; with lifetime, it's a time window. There is no revocation and no replay protection. Treat a leaked link as a leaked password: short lifetimes, HTTPS only, and a password-based signature_properties-style invalidation (rotate via a user field / secret rotation) if you need to revoke.
  • Secret rotation kills outstanding links. The hash is keyed off %kernel.secret%. Changing it (or having different secrets per environment) invalidates everything already sent — expected in staging, surprising in prod if you rotate secrets casually.
  • The token lives in the URL. It will show up in access logs, proxy logs, browser history, and any outbound Referer. Always redirect to a clean URL, set a referrer policy, and avoid GET links in contexts where the URL is shared onward.
  • Already-authenticated users. Verify the listener's behaviour when a session user is present — depending on placement it may skip or re-authenticate as the token's user. Don't mix auto-login into a firewall where long-lived sessions matter without testing the swap.
  • Firewall config is compiled. After editing security.yaml or the bundle config, bin/console cache:clear — a stale container is the most common "my token doesn't work" cause.
  • Router context in CLI. Links generated from commands/messengers use the default request context (localhost). Set host/scheme/base URL on router.request_context.* or $urlGenerator->getContext() before generating.
  • Debugging path: bin/console debug:firewall main (4.4+) or the web profiler's Security panel (_security_main), plus the security log channel. If the token is rejected, drop a breakpoint/log in vendor/jmikola/auto-login-bundle/Security/AutoLoginListener.php — the class is small and readable, and the failure is almost always identifier mismatch, expired lifetime, or secret mismatch.
  • Testing. Functional tests via KernelBrowser are straightforward: generate a token with the test container's generator (same %kernel.secret%), request /$route?autologin=$token, assert the redirect and the authenticated user. Pin the lifetime in test config so tokens don't expire mid-suite.
  • Zero dependents and a 2020 release means no upstream fixes are coming. Audit the listener yourself (it's a few hundred lines) before putting it in front of real accounts, and keep a fork/PR path in mind if you need a security patch.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
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
cgv/localized-resource