26th Nov 2025
Authentication for admin panels must be separate, secure, and simple to maintain. In this tutorial you’ll learn how to implement a complete admin forgot-password & reset-password flow for a custom admins table and custom admin guard in Laravel 12.
Table of contents
-
Why custom admin password reset?
-
How the flow works (theory)
-
Database:
password_reset_tokensmigration -
Routes (admin group)
-
Controller methods (forget, submit, show reset, submit reset)
-
Important Blade snippets (Forgot Password, Reset Password, Logout link)
-
Email template (HTML)
-
Security best practices
-
Testing & debugging checklist
-
FAQ
1. Why a custom admin password reset?
Most Laravel apps use the default users flow. But admin accounts should be isolated:
-
Admins have elevated privileges — losing an admin password is high risk.
-
You may want different token lifetime, separate email templates, throttling and audit logs.
-
A separate
adminstable and guard prevents accidental cross-authentication and lets you customize behavior for backend users.
This tutorial continues from your existing admin auth (separate admins table and admin guard) and shows a production-ready forgot/reset password flow.
2. How the flow works — theory (quick)
-
Admin clicks Forgot password and submits email.
-
Server checks that email exists in
admins. -
Server creates a one-time token (we’ll store a hashed token in DB and send the plain token in the email link).
-
Email contains link:
/admin/login/reset-password/{token}. -
When admin opens link, server finds matching hashed token and checks expiry.
-
Admin submits new password — server verifies token again and updates password (hashed with
bcrypt). -
All tokens for that email are deleted.
Why hash token in DB? If your DB is leaked, hashed tokens prevent attackers from using stored tokens directly. You still send the plain token in email only. Verification uses Hash::check().
Token expiry & rate-limiting are essential to prevent abuse.
3. Database migration: password_reset_tokens
Create migration:
Migration file (important parts):
Run:
4. Routes — admin group
Add these to routes/web.php inside the admin prefix:
use App\Http\Controllers\Admin\AuthController;
Route::prefix('admin')->group(function () {
Route::get('login', [AuthController::class, 'login'])->name('admin.login');
Route::post('login/submit', [AuthController::class, 'login_submit'])->name('admin.login.submit');
// Forgot & reset
Route::get('login/forget-password', [AuthController::class, 'forgetpass'])->name('admin.forgetpass');
Route::post('login/forget-password/submit', [AuthController::class, 'submitforgetpass'])->name('admin.forgetpass.submit');
Route::get('login/reset-password/{token}', [AuthController::class, 'show_reset_pass_form'])->name('admin.reset.password.get');
Route::post('login/reset-password', [AuthController::class, 'submit_reset_pass_form'])->name('admin.reset.password.post');
// Logout (POST)
Route::post('logout', [AuthController::class, 'logout'])->name('admin.logout');
});
Notes:
-
Logout must be
POSTfor CSRF protection. -
Reset POST accepts token via hidden input (safer pattern).
5. Controller: AuthController methods
Add these methods in App\Http\Controllers\Admin\AuthController. Required imports (top of file):
5.1 Show forgot password view
public function forgetpass()
{
return check_admin_auth('adminpanel.auth.forget_password'); // your helper that redirects if logged in
}
5.2 Handle forgot password submit
5.3 Show reset password form
5.4 Handle reset password submit
5.5 Logout method (if not present)
6. Blade snippets
6.1 Login password field
6.2 Forgot Password Blade (adminpanel/auth/forget_password.blade.php)
6.3 Reset Password Blade (adminpanel/auth/reset_password.blade.php)
6.4 Logout link
7. Email template
resources/views/adminpanel/emails/forget_password.blade.php:
8. Security best practices
-
Hash tokens in DB. We store
Hash::make($token)and validate withHash::check($plainToken, $hashedToken). -
Short expiry. 60 minutes is standard. Enforce expiry checks.
-
Rate limit resets. Use
RateLimiteror throttle middleware to prevent spam. -
Delete tokens on success. Remove all tokens for the email after successful reset.
-
Strong password rules. Minimum 8 characters; consider adding
regexrules for complexity. -
HTTPS only. Ensure
APP_URLuseshttps://so email links use HTTPS. -
Audit logs. Log when reset is requested and completed (admin email, IP, timestamp).
-
Email deliverability. Use SMTP provider (SendGrid, Mailgun) and test with Mailtrap during development.
-
CSRF. Keep forms protected with
@csrf. -
Logout guard. Use
Auth::guard('admin')->logout()and protect admin routes withauth:admin.
9. Testing & debugging checklist
-
Migrate
password_reset_tokensand create a test admin entry. -
Submit forget-password for the admin email; confirm DB has hashed token and
created_at. -
Receive email (use Mailtrap in dev); click link.
-
Open reset form; submit new password; verify admin can login with new password.
-
Confirm tokens cleared after reset.
-
Test invalid/expired token behavior.
-
Attempt rate-limit exceed to ensure message shows.
-
Test logout link works and returns to login.
10. FAQs
Q: Should I use Laravel Password Broker instead?
A: For long-term maintainability, use Laravel’s Password Broker configured for the admins provider — it handles many details (throttling, expiry). The custom approach above gives finer control and is fine if you need a separate flow.
Q: Why store hashed token instead of plain token?
A: Hashing tokens prevents token misuse if DB leaks. Only the plain token sent by email is usable and verified using Hash::check().
Q: How long should tokens live?
A: 60 minutes is common. Shorter lifetimes are more secure; longer are more user friendly.
Leave A Reply
Your email address will not be published. Required fields are marked