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

Password Generator Laravel Package

juststeveking/password-generator

A lightweight PHP package for generating secure, customizable passwords in Laravel or standalone projects. Configure length and character sets, generate readable or memorable passwords, and integrate with a simple API.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and pin to the 1.0 line. There is one release (2022-11-16), so treat the constraint as a deliberate freeze rather than a range you expect to grow:

composer require juststeveking/password-generator:^1.0

No migrations, no credentials, no service provider registration on modern Laravel — package discovery handles it. The only setup step worth doing is publishing the config if one ships, so policy values live in config/ instead of call sites:

php artisan vendor:publish --tag=password-generator-config

Where to look first — and this is not optional. Before the first call site, open vendor/juststeveking/password-generator/src and read the generator itself. The entire value of this dependency is that output comes from a CSPRNG. Grep for the failure modes:

grep -rnE "rand\(|mt_rand|str_shuffle|shuffle\(" vendor/juststeveking/password-generator/src
grep -rnE "random_int|random_bytes" vendor/juststeveking/password-generator/src

If str_shuffle, shuffle, rand, or mt_rand appear anywhere in the generation path, stop — the package does not clear the bar and you should fall back to Str::password() or a short owned implementation. If only random_int/random_bytes appear, continue.

Then confirm the API surface in tinker rather than trusting the README, because the exact fluent method names are the one thing you must not guess:

php artisan tinker
>>> $p = new JustSteveKing\PasswordGenerator\Password(); // or the facade
>>> get_class_methods($p);
>>> (string) $p->length(20)->numbers()->symbols()->generate();

First use case: test fixtures and seeders. Start where a weak or repeated password costs nothing — model factories, demo-tenant seeding, CI bootstrap scripts. It gives you real usage across a few days with zero security exposure while you learn the API's edges, and it is trivially revertible.

// database/factories/UserFactory.php
public function withTemporaryPassword(): static
{
    return $this->state(fn () => [
        'password' => Hash::make(Password::length(24)->numbers()->symbols()->generate()),
        'must_change_password' => true,
    ]);
}

Implementation Patterns

Wrap it before the second call site. The package is a twenty-line problem behind a fluent API; the wrapper is what you actually maintain. Define a single interface so policy floors are enforced in one place and the dependency stays swappable:

// app/Support/Password/PasswordPolicy.php
interface PasswordPolicy
{
    public function generate(): string;
}

// app/Support/Password/PackagePasswordPolicy.php
final class PackagePasswordPolicy implements PasswordPolicy
{
    public function __construct(private readonly int $minLength = 20) {}

    public function generate(): string
    {
        $length = max($this->minLength, (int) config('auth.generated_password_length', 20));

        return (string) Password::length($length)
            ->numbers()
            ->symbols()
            ->generate();
    }
}

Bind it once, in a dedicated provider, not in AppServiceProvider:

$this->app->singleton(PasswordPolicy::class, PackagePasswordPolicy::class);

Every call site now depends on your interface. When the maintainer goes quiet, or Laravel's Str::password() grows past your policy, you change one file.

Cast to string at the boundary, always. The result is a stringable object. If it reaches json_encode, a log context array, or an Eloquent attribute without an explicit cast you get either an object-in-JSON error or — worse — an __toString on a password that ends up somewhere it shouldn't. The (string) in the wrapper above is load-bearing; keep it there and never return the raw object.

Provisioning command pattern. The highest-value real use is admin-provisioned temporary credentials:

public function handle(PasswordPolicy $policy): int
{
    $password = $policy->generate();

    $user = User::create([
        'email' => $this->argument('email'),
        'password' => Hash::make($password),
        'must_change_password' => true,
        'password_expires_at' => now()->addHours(24),
    ]);

    // Print to the operator's terminal only. Never Log::info it,
    // never put it in a queued notification payload you can't purge.
    $this->line("Temporary password for {$user->email}: {$password}");

    return self::SUCCESS;
}

The password leaves the process once, through stdout, to a named human. That is the whole threat model — keep it that way.

Deterministic tests via the container. Because call sites resolve PasswordPolicy, tests never touch the package:

$this->instance(PasswordPolicy::class, new class implements PasswordPolicy {
    public function generate(): string { return 'fixed-test-password'; }
});

One property test on the real implementation, so a future release cannot silently weaken invariants:

public function test_generated_passwords_meet_policy(): void
{
    $policy = app(PasswordPolicy::class);

    foreach (range(1, 500) as $_) {
        $pw = $policy->generate();
        $this->assertGreaterThanOrEqual(20, strlen($pw));
        $this->assertMatchesRegularExpression('/[0-9]/', $pw);
        $this->assertMatchesRegularExpression('/[^A-Za-z0-9]/', $pw);
    }
}

Run it against a large enough sample that a probabilistic composition bug actually shows. 500 is enough to catch a class being dropped from the pool; it is not enough to prove entropy.

Gotchas and Tips

Composition is the quiet failure mode. Shuffling from a concatenated pool gives you probabilistic class coverage, not guaranteed. At length 20 with four classes the odds of a missed class are low, which is exactly why the bug survives review — but at length 8 or with a policy that mandates "at least one symbol," a pool-shuffle will eventually violate it. If the source does not enforce composition, enforce it in PackagePasswordPolicy (regenerate on failure, or splice one char per class and shuffle yourself) — and accept that you now own the security-relevant half of the library.

Check the minimum-length behaviour explicitly. Call ->length(4) and ->length(0) and see what comes back. A generator that happily returns four characters is a footgun waiting for someone to wire a config value. Your wrapper's max() guard is the defence; do not rely on upstream.

Spaces are a trap. Enabling spaces in a password that will travel through an HTML form, a CSV export, a YAML config, or a trim() on the receiving end is a support ticket. Default them off in your wrapper and only enable per-flow with intent.

Ambiguous characters. 0/O, 1/l/I cause real-world transcription failures for the human-provisioned-credential flow, which is your primary use case. Check whether the package exposes a pool you can prune; if not, note it as a known limitation rather than fighting it.

Staleness is a maintenance cost, not a blocker. Single maintainer, zero dependents, no release since November 2022, and a 1.0.0 changelog that is only a link to commits. Pin ^1.0, diff upstream before any bump, and accept that no security patch path exists. The code is small enough to vendor or fork — budget the hour now, not during an incident. Verify the PHP constraint against both your current runtime and your next upgrade target, since nobody is going to modernise it for you.

Don't let adoption imply coverage it doesn't have. This generates strings. It does not estimate strength, check breach lists, hash, rate-limit, or support client-side zero-knowledge generation. If someone asks "so password security is handled?", the answer is no — this is one primitive in a flow that still needs hashing (Hash::make), expiry, and a forced rotation.

Compare against the native helper before you commit. Str::password() satisfies many policies with zero dependency. If it meets yours, take it. This package earns its place only when you want the same generator available in standalone ops/CI scripts outside the framework, or when a config-driven fluent API genuinely reads better at your call sites than the helper does.

Config caching. If a published config drives length and character classes, a change requires php artisan config:cache in production. A policy change that silently doesn't take effect because the config is cached is the sort of thing you discover in a postmortem — put the policy floor in code (minLength on the wrapper) and the tunable in config.

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.
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
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle