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

Laravel Human Keys Laravel Package

oneduo/laravel-human-keys

Generate human-friendly, Stripe-style public keys for your Eloquent models, hiding sequential IDs behind readable, non-guessable identifiers. Add a trait, set a prefix, and get unique keys for safer URLs and APIs.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package and publish its config (and migration, if your version ships a human_keys table):

composer require oneduo/laravel-human-keys

php artisan vendor:publish --tag="human-keys-config"
php artisan vendor:publish --tag="human-keys-migrations"
php artisan migrate

If the tags are not registered in your version, publish by provider:

php artisan vendor:publish --provider="Oneduo\LaravelHumanKeys\HumanKeysServiceProvider"

Add the trait to any model that should expose a Stripe-style public identifier:

use Oneduo\LaravelHumanKeys\Traits\HasHumanKeys;

class User extends Model
{
    use HasHumanKeys;
}

The first practical use case is replacing sequential IDs in public-facing surfaces. After creation, the model exposes a key such as usr_7fK2mQ9xLp:

$user = User::create([...]);

$user->key; // "usr_7fK2mQ9xLp"

Where to look first:

  • config/human-keys.php — prefix mapping, key length, generator class, and any per-model overrides.
  • The HasHumanKeys trait — it contains the model event hook that creates the key.
  • The published migration/model — tells you whether keys live on the model table or in a polymorphic human_keys table.

Implementation Patterns

Use keys as the public API identifier, not the primary key. Keep auto-increment IDs internal and expose the human key in resources:

class UserResource extends JsonResource
{
    public function toArray($request): array
    {
        return [
            'id' => $this->key,
            'name' => $this->name,
        ];
    }
}

Configure prefixes per model. Stripe-style keys are only useful if they are self-describing. Set a short, stable prefix for each model:

// config/human-keys.php
'prefixes' => [
    User::class => 'usr',
    Organization::class => 'org',
    Invoice::class => 'inv',
],

For one-off exceptions, override the prefix on the model itself (property or method, depending on the package version):

protected string $humanKeyPrefix = 'adm';

Bind routes by key. If the key is stored on the model table, use Laravel’s route key:

public function getRouteKeyName(): string
{
    return 'key';
}

If keys live in a separate polymorphic table, implement resolveRouteBinding() to query the relation instead of relying on getRouteKeyName().

Backfill existing records. New keys are usually generated on the creating/created event, so existing rows will not have one. Write a one-off command that iterates models and generates keys:

User::query()
    ->whereDoesntHave('humanKeys')
    ->chunkById(500, fn ($users) => $users->each->generateHumanKey());

Use keys in outbound communication. Human keys are ideal for support tickets, webhook payloads, logs, and emails: “Your account org_8fJ2...” is easier to trace than id: 1842. Use the key consistently in logs and error tracking so support can search by it.

Custom generation belongs in a generator class. Rather than overriding model methods, point the config at a custom generator when you need a different alphabet, length, or checksum:

'generator' => App\Support\Keys\UrlSafeKeyGenerator::class,

This keeps generation logic testable and consistent across models.

Gotchas and Tips

A human key is not a secret. It is an identifier, not an authentication token. Do not use it for password resets, signed URLs, or API authentication. Its entropy and length are tuned for readability, not security.

Enforce uniqueness in the database. Random collisions are rare, but the key column/table should have a unique index. Retry generation on a unique-constraint violation rather than assuming the first attempt always succeeds.

Bulk inserts bypass model events. Model::insert() and upsert() will not fire the trait’s creation hook. Use create()/save() per model, or explicitly generate keys before bulk writing.

Existing data needs a backfill plan. Adding the trait to a model with thousands of rows does not retroactively create keys. Plan the migration and backfill together, and make lookups tolerate a missing key during the transition.

Watch for N+1 queries. If keys are stored in a polymorphic table, accessing $model->key in a loop may lazy-load the relation. Eager load humanKeys (or the singular relation) anywhere you serialize a collection.

Changing prefixes or length only affects new keys. Existing keys keep their old prefix. Treat prefixes as a stable contract once external systems or customers have seen them.

Config caching matters. In production, run php artisan config:cache after changing config/human-keys.php. A stale cache is a common reason a new prefix appears not to apply.

Route binding and soft deletes interact. If you bind by key, confirm that soft-deleted models are excluded (or included) as intended. The same applies to any custom resolveRouteBinding() implementation.

Testing tip. Assert the shape, not the exact value: $this->assertMatchesRegularExpression('/^usr_[A-Za-z0-9]+$/', $user->key). For deterministic tests, bind a fake generator in the container or override the config generator with a test double.

Extension points. The config’s generator class and the model prefix override are the intended customization seams. Prefer those over editing package files or duplicating key-generation logic in your models.

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.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels