Password Reset
AuthKit provides a configurable, driver-based password reset system that supports both:
- reset-link flows
- reset-token / reset-code flows
The flow is built to be privacy-aware, extensible, and fully configuration-driven.
Overview
Password reset in AuthKit has three main phases:
- Requesting a password reset
- Receiving a reset link or reset code
- Completing the password reset
The system is controlled through:
authkit.password_reset.driver
authkit.password_reset.ttl_minutes
authkit.password_reset.delivery
authkit.password_reset.post_request
authkit.password_reset.post_reset
authkit.password_reset.user_resolver
authkit.password_reset.policy
authkit.password_reset.password_updater
authkit.password_reset.privacySupported drivers:
linktoken
The link driver sends a reset URL containing the raw token.
The token driver sends a reset code or token that the user enters manually.
Flow Overview
At a high level, the password reset flow works like this:
- the user submits a forgot-password request
- AuthKit resolves whether reset can be requested
- AuthKit creates a pending password reset token
- AuthKit dispatches a password reset event for delivery
- the user follows a link or enters a token
- AuthKit validates and consumes the token
- AuthKit resolves the target user
- AuthKit updates the password
- AuthKit optionally logs the user in
- AuthKit redirects according to configuration
Pending Password Reset State
AuthKit tracks reset state through:
Xul\AuthKit\Support\PendingPasswordResetThis class is responsible for:
- creating reset tokens
- tracking whether a reset flow is pending for an email
- peeking at a token without consuming it
- consuming a token as a single-use credential
- clearing pending presence after successful consumption
Driver behavior
For the link driver:
- AuthKit generates a long token
- that token is typically embedded in a reset URL
For the token driver:
- AuthKit generates a short code or token
- the user manually enters it on the reset page
Presence tracking
AuthKit also stores a short-lived presence marker keyed by email so that web pages and middleware can confirm that a reset flow exists without knowing the raw token.
Routes
Password reset routes are resolved from configuration.
Relevant web route names:
authkit.route_names.web.password_forgot
authkit.route_names.web.password_forgot_sent
authkit.route_names.web.password_reset
authkit.route_names.web.password_reset_token_page
authkit.route_names.web.password_reset_success
authkit.route_names.web.loginRelevant API route names:
authkit.route_names.api.password_send_reset
authkit.route_names.api.password_verify_token
authkit.route_names.api.password_resetThese routes are used for:
- the forgot-password page
- the post-request confirmation page
- the reset form page
- the token entry page
- the password reset success page
- the send-reset action
- the token verification action
- the reset-password action
Requesting a Password Reset
Forgot-password submissions are handled by:
Xul\AuthKit\Http\Controllers\Api\PasswordReset\ForgotPasswordControllerThat controller delegates to:
Xul\AuthKit\Actions\PasswordReset\RequestPasswordResetActionWhat the request action does
The request action:
- reads the normalized identity from the mapped payload
- resolves the active reset driver from authkit.password_reset.driver
- checks whether reset requests are allowed through the configured policy
- resolves the user through the configured user resolver
- supports privacy mode so account existence is not revealed
- creates a pending reset token
- builds a reset URL when the active driver is link
- dispatches a password reset event for delivery
- returns a standardized action result
Privacy mode
Privacy behavior is controlled by:
authkit.password_reset.privacy.hide_user_existence
authkit.password_reset.privacy.generic_messageWhen privacy protection is enabled:
- AuthKit returns the same public response whether or not a user exists
- reset tokens and events are only created when a real user exists
- the user-facing message remains intentionally generic
This helps reduce account enumeration risk.
Password Reset Delivery
AuthKit does not deliver reset links or reset tokens directly from the action. Instead, it dispatches:
Xul\AuthKit\Events\AuthKitPasswordResetRequestedDelivery is controlled through:
authkit.password_reset.delivery.use_listener
authkit.password_reset.delivery.listener
authkit.password_reset.delivery.notifier
authkit.password_reset.delivery.mode
authkit.password_reset.delivery.queue_connection
authkit.password_reset.delivery.queue
authkit.password_reset.delivery.delayPackaged listener
When the packaged listener is enabled, AuthKit uses:
Xul\AuthKit\Listeners\SendPasswordResetNotificationThat listener delegates delivery to the configured notifier implementing:
Xul\AuthKit\Contracts\PasswordReset\PasswordResetNotifierContractDelivery modes
Supported modes:
syncqueueafter_response
If queued delivery is enabled, AuthKit may use:
Xul\AuthKit\Jobs\SendPasswordResetNotificationJobPackaged notifier
The default notifier is:
Xul\AuthKit\Support\Notifiers\PasswordResetNotifierIt uses Laravel notifications and routes delivery to the provided email address.
Packaged notifications include:
linkdriver:
Xul\AuthKit\Notifications\AuthKitPasswordResetLinkNotificationtokendriver:
Xul\AuthKit\Notifications\AuthKitPasswordResetTokenNotificationPassword Reset Pages
AuthKit supports two common reset experiences.
Link driver page
For the link driver, the user typically opens a reset URL and lands on the reset form page. The page usually receives:
tokenemailThe actual token is not validated on the GET page. Validation and consumption happen only when the user submits the reset form.
Token driver page
For the token driver, the user is taken to a token-entry page where they provide:
emailtokennew passwordpassword confirmation
Depending on your UI flow, token verification and password reset may happen together in one submission.
Middleware Protection
Reset pages that require a pending reset context are protected by:
Xul\AuthKit\Http\Middleware\EnsurePendingPasswordResetMiddlewareThis middleware checks:
- that an email context exists in the query string
- that a pending password reset presence exists for that email
If no valid pending context exists, AuthKit redirects to:
authkit.route_names.web.password_forgotImportant: this middleware does not validate the reset token on the web route. Token validation happens only on submission to the API/action endpoint.
Link Driver Reset Flow
The link-driver reset submission is handled by:
Xul\AuthKit\Http\Controllers\Api\PasswordReset\ResetPasswordControllerThat controller delegates to:
Xul\AuthKit\Actions\PasswordReset\ResetPasswordActionWhat the reset action does
Xul\AuthKit\Actions\PasswordReset\ResetPasswordAction:- reads the normalized mapped attributes
- checks whether reset is allowed through the configured policy
- consumes the reset token as a single-use credential
- resolves the target user through the configured resolver
- persists mapper-approved attributes when applicable
- updates the password through the configured password updater
- optionally logs the user in
- resolves the correct post-reset redirect
Token Driver Reset Flow
Token-driver reset verification is handled by:
Xul\AuthKit\Http\Controllers\Api\PasswordReset\VerifyPasswordResetTokenControllerThat controller delegates to:
Xul\AuthKit\Actions\PasswordReset\VerifyPasswordResetTokenActionWhat the token action does
Xul\AuthKit\Actions\PasswordReset\VerifyPasswordResetTokenAction:- requires the active driver to be token
- checks that a pending reset context exists
- enforces the configured reset policy
- applies throttling for repeated token verification attempts
- validates and consumes the token
- resolves the target user
- persists mapper-approved attributes when applicable
- updates the password through the configured password updater
- optionally logs the user in
- returns the correct post-reset redirect
Token Verification Throttling
For token-driver flows, AuthKit applies throttling through:
authkit.password_reset.token.max_attempts
authkit.password_reset.token.decay_minutesThis protects short reset codes from brute-force attempts. If too many verification attempts occur, AuthKit returns a throttled failure response instead of continuing verification.
Validation
Password reset validation is handled by request classes for each context, such as:
- forgot password
- reset password
- reset token verification
AuthKit builds validation from:
authkit.schemas.password_forgot
authkit.schemas.password_reset
authkit.schemas.password_reset_token
authkit.validation.providers.password_forgot
authkit.validation.providers.password_reset
authkit.validation.providers.password_reset_tokenBecause the system is schema-driven:
- form rendering and validation stay aligned
- custom validation behavior can be supplied through providers
Any custom validation provider must implement:
Xul\AuthKit\Contracts\Validation\RulesProviderContractPayload Mapping
AuthKit maps password reset input through mapper contexts such as:
- password_forgot
- password_reset
- password_reset_token
These are configured under:
authkit.mappers.contexts.password_forgot
authkit.mappers.contexts.password_reset
authkit.mappers.contexts.password_reset_tokenMapped payload building is handled through:
Xul\AuthKit\Support\Mappers\MappedPayloadBuilderBy default, password reset fields are treated as non-persistable. However, the actions remain persistence-aware so that consumer-defined mappers can mark additional fields as persistable when needed.
Any custom mapper must implement:
Xul\AuthKit\Contracts\Mappers\PayloadMapperContractUser Resolution
AuthKit resolves the user involved in the reset flow through:
Xul\AuthKit\Contracts\PasswordReset\PasswordResetUserResolverContractThis allows the password reset system to support:
- non-standard identity fields
- multiple user sources
- tenant-aware applications
- custom authentication setups
Configuration:
authkit.password_reset.user_resolver.strategy
authkit.password_reset.user_resolver.resolver_classIf you provide a custom resolver, it must implement:
Xul\AuthKit\Contracts\PasswordReset\PasswordResetUserResolverContractPolicy Checks
AuthKit supports application-specific reset rules through:
Xul\AuthKit\Contracts\PasswordReset\PasswordResetPolicyContractThis policy is used to determine:
- whether a reset may be requested
- whether a password may be reset
Configuration:
authkit.password_reset.policyTypical uses:
- block reset for suspended accounts
- require certain account state before allowing reset
- enforce internal security rules
Any custom policy must implement:
Xul\AuthKit\Contracts\PasswordReset\PasswordResetPolicyContractPassword Updates
Actual password persistence is delegated to:
Xul\AuthKit\Contracts\PasswordReset\PasswordUpdaterContractConfiguration:
authkit.password_reset.password_updater.class
authkit.password_reset.password_updater.refresh_remember_tokenThis exists so applications can customize:
- hashing strategy
- remember-token refresh
- audit trails
- password history logic
- additional security operations
Any custom updater must implement:
Xul\AuthKit\Contracts\PasswordReset\PasswordUpdaterContractReset URLs
For link-driver flows, reset URL generation is delegated to:
Xul\AuthKit\Contracts\PasswordReset\PasswordResetUrlGeneratorContractConfiguration:
authkit.password_reset.url_generatorThis allows you to customize:
- route shape
- frontend domain
- signed parameter handling
- external reset frontends
Any custom URL generator must implement:
Xul\AuthKit\Contracts\PasswordReset\PasswordResetUrlGeneratorContractPost-Request Redirects
What happens after a forgot-password request is controlled by:
authkit.password_reset.post_request.mode
authkit.password_reset.post_request.sent_route
authkit.password_reset.post_request.token_routeSupported modes:
sent_pagetoken_page
Behavior
When mode is sent_page:
- AuthKit redirects to a confirmation page such as “check your email”
When mode is token_page:
- AuthKit redirects directly to the token-entry page for token-driver flows
Post-Reset Redirects
What happens after a successful password reset is controlled by:
authkit.password_reset.post_reset.mode
authkit.password_reset.post_reset.redirect_route
authkit.password_reset.post_reset.login_route
authkit.password_reset.post_reset.success_route
authkit.password_reset.post_reset.login_after_reset
authkit.password_reset.post_reset.rememberSupported modes:
redirectsuccess_page
Redirect resolution
For reset completion, AuthKit resolves redirects in this order based on configuration:
- configured redirect route when mode is redirect
- configured login fallback when needed
- success page route when mode is success_page
- dashboard-style redirect when automatic login after reset is enabled
Automatic Login After Reset
AuthKit can optionally authenticate the user immediately after a successful reset.
Controlled by:
authkit.password_reset.post_reset.login_after_reset
authkit.password_reset.post_reset.remember
authkit.auth.guardWhen enabled:
- AuthKit logs the user into the configured guard
- dispatches:
Xul\AuthKit\Events\AuthKitLoggedInThis behavior is available in both reset actions.
Key Action Classes
The main packaged action classes are:
Request reset
Xul\AuthKit\Actions\PasswordReset\RequestPasswordResetActionStarts the reset flow and dispatches delivery.
Verify token and reset
Xul\AuthKit\Actions\PasswordReset\VerifyPasswordResetTokenActionUsed for token-driver flows where token verification and password reset happen together.
Reset password
Xul\AuthKit\Actions\PasswordReset\ResetPasswordActionUsed for standard reset completion, especially in link-driver flows.
Key Controllers
The main packaged controllers are:
- Forgot password
Xul\AuthKit\Http\Controllers\Api\PasswordReset\ForgotPasswordController- Verify reset token
Xul\AuthKit\Http\Controllers\Api\PasswordReset\VerifyPasswordResetTokenController- Reset password
Xul\AuthKit\Http\Controllers\Api\PasswordReset\ResetPasswordControllerThese controllers remain thin and delegate the real flow orchestration to the corresponding actions.
Example Configuration
'password_reset' => [
'driver' => 'link',
'ttl_minutes' => 30,
'delivery' => [
'use_listener' => true,
'listener' => \Xul\AuthKit\Listeners\SendPasswordResetNotification::class,
'notifier' => \Xul\AuthKit\Support\Notifiers\PasswordResetNotifier::class,
'mode' => 'sync',
'queue_connection' => null,
'queue' => null,
'delay' => 0,
],
'url_generator' => \Xul\AuthKit\Support\PasswordReset\PasswordResetUrlGenerator::class,
'policy' => \Xul\AuthKit\Support\PasswordReset\PermissivePasswordResetPolicy::class,
'token' => [
'max_attempts' => 5,
'decay_minutes' => 1,
],
'post_request' => [
'mode' => 'sent_page',
'sent_route' => 'authkit.web.password.forgot.sent',
'token_route' => 'authkit.web.password.reset.token',
],
'post_reset' => [
'mode' => 'success_page',
'redirect_route' => null,
'login_route' => 'authkit.web.login',
'success_route' => 'authkit.web.password.reset.success',
'login_after_reset' => false,
'remember' => true,
],
'user_resolver' => [
'strategy' => 'provider',
'resolver_class' => null,
],
'password_updater' => [
'class' => null,
'refresh_remember_token' => true,
],
'privacy' => [
'hide_user_existence' => true,
'generic_message' => 'If an account exists for this email, password reset instructions have been sent.',
],
],Override Points
AuthKit allows targeted overrides for the password reset flow.
Custom notifier
Must implement:
Xul\AuthKit\Contracts\PasswordReset\PasswordResetNotifierContractCustom policy
Must implement:
Xul\AuthKit\Contracts\PasswordReset\PasswordResetPolicyContractCustom URL generator
Must implement:
Xul\AuthKit\Contracts\PasswordReset\PasswordResetUrlGeneratorContractCustom user resolver
Must implement:
Xul\AuthKit\Contracts\PasswordReset\PasswordResetUserResolverContractCustom password updater
Must implement:
Xul\AuthKit\Contracts\PasswordReset\PasswordUpdaterContractCustom validation providers
Must implement:
Xul\AuthKit\Contracts\Validation\RulesProviderContractCustom payload mappers
Must implement:
Xul\AuthKit\Contracts\Mappers\PayloadMapperContractBest Practices
- Keep privacy mode enabled in production unless you have a very specific reason not to.
- Use the
linkdriver for conventional browser-based reset flows. - Use the
tokendriver for OTP-style or API-first reset experiences. - Keep
authkit.password_reset.ttl_minutesshort enough for security but long enough for usability. - Use a custom user resolver when your application does not resolve reset users through a standard provider lookup.
- Use a custom policy for business rules instead of hardcoding those checks into controllers or actions.
- Use a custom password updater when you need password history, custom hashing behavior, or security audit hooks.
- Prefer extending delivery through the notifier and listener system instead of modifying the reset actions directly.