whilesmart/laravel-user-authentication
A Laravel package that provides ready-made user authentication flows, including registration, login, logout, email verification, and password reset, with token-based API support to help you add secure auth to Laravel apps faster.
composer require whilesmart/laravel-user-authentication
Find the service provider name first. With a small package it's faster to look than to guess:
php artisan vendor:publish --list | grep -i whilesmart
Then publish config and migrations:
php artisan vendor:publish --provider="Whilesmart\UserAuthentication\UserAuthenticationServiceProvider"
php artisan migrate
Read routes/ before you read anything else. This is an API-first package, so the route file is the real contract — it tells you the endpoints, the controller methods, and the middleware stack in one screen. Confirm what got registered:
php artisan route:list --path=api
Check the config file. Expect knobs for the user model class, token TTL/expiry, enabled auth features (registration, email verification, password reset), and Socialite provider list. Anything you don't set explicitly is a default you're inheriting from a package with ~0 dependents — read them, don't assume them.
First use case: hit POST /api/register (or /api/login) with a JSON body, get a token back, then call a protected route with Authorization: Bearer <token>. Do this with curl/HTTPie before wiring any frontend — it isolates "package misconfigured" from "client misconfigured".
Run composer show whilesmart/laravel-user-authentication and pin the version you validated ("whilesmart/laravel-user-authentication": "1.x" rather than ^1.0) until you've read enough of the source to trust minor bumps.
Token issuance and protected routes. The package is designed so authentication is a token endpoint, not a session. Keep your app's own controllers behind standard Laravel auth middleware and let the package own only the credential-exchange surface:
// routes/api.php — your app routes
Route::middleware('auth:sanctum')->group(function () {
Route::get('/me', fn (Request $r) => $r->user());
Route::apiResource('/projects', ProjectController::class);
});
Verify which guard the package actually issues tokens for (config/auth.php → guards.api.driver) and align your protected routes to that guard. A mismatch here produces 401s that look like token bugs.
Swap the user model via config, don't fork. Most packages of this shape resolve the model from config. Point it at your existing App\Models\User so relations, casts, and policies keep working:
// config/user-authentication.php
'user_model' => App\Models\User::class,
If your users table already exists, edit the published migration to a Schema::table alteration before running it, or skip the migration and hand-add the columns it expects (verify names against the migration file).
Socialite: keep the callback stateless. For API consumers the redirect flow is awkward. Two workable patterns:
config/services.php, let the package's callback route exchange the code, and return your own token from there.Socialite::driver($provider)->stateless()->userFromToken($token). The package's Socialite support is the starting point; expect to write the token-exchange controller yourself.Never put the OAuth secret in the client. And confirm the callback URL matches what's registered with the provider exactly — including trailing slashes and http vs https.
OpenAPI as the source of truth. The package ships an OpenAPI description. Generate your typed client from it rather than hand-writing requests:
npx openapi-typescript vendor/whilesmart/laravel-user-authentication/openapi.yaml -o types/auth.d.ts
If you extend the auth surface (extra fields on register, MFA, etc.), copy the spec into your own openapi/ folder and merge — do not edit files inside vendor/, they vanish on composer update.
Testing. Use RefreshDatabase and assert on the JSON contract, not on package internals:
it('registers and returns a token', function () {
$this->postJson('/api/register', [
'name' => 'Ada', 'email' => '[email protected]',
'password' => 'secret-password', 'password_confirmation' => 'secret-password',
])->assertCreated()->assertJsonStructure(['token']);
});
For tests that shouldn't send real mail, use Mail::fake() and Notification::fake() — verification and reset flows will hit your mailer.
/api/login or /api/register, one will silently shadow the other based on registration order in bootstrap/app.php / RouteServiceProvider. Run php artisan route:list and check for duplicates. Most packages expose a config flag to disable their route registration — prefer that over editing vendor files.php artisan config:cache will freeze your defaults. After changing .env values that map into the package config, re-run php artisan config:clear. This is the #1 cause of "my token TTL change did nothing".users table. On an established app, read it before running migrate; a naive run can attempt Schema::create('users') and fail, or worse, succeed on a fresh DB and diverge from production. Diff it against your real schema.state parameter. Without stateless(), API requests fail with a InvalidStateException. Also ensure the callback route is outside your auth middleware group.APP_URL — signed URLs generated with the wrong host produce links that 404 or fail signature validation. Set APP_URL correctly in every environment, including staging.401 → token missing/expired/wrong guard. 403 → authenticated but unauthorized (policy/gate, not the package). 419/CSRF → you're accidentally hitting a web middleware route from an API client. Check route:list for the middleware column before touching package code.Login, Registered, Verified) via listeners. If the package dispatches its own events, hook those rather than overriding controllers.How can I help you explore Laravel packages today?