# Search Results

## Fortify Authentication Customizing User Authentication Authentication Guard
Fortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md

#### Authentication Guard

You may customize the authentication guard used by Fortify within your application's `fortify` configuration file. However, you should ensure that the configured guard is an implementation of `Illuminate\Contracts\Auth\StatefulGuard`. If you are attempting to use Laravel Fortify to authenticate an SPA, you should use Laravel's default `web` guard in combination with [Laravel Sanctum](https://laravel.com/docs/sanctum).

---

## Passwords Routing Requesting the Password Reset Link Handling the Form Submission
Passwords | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/passwords.md

#### Handling the Form Submission

Next, we will define a route that handles the form submission request from the "forgot password" view. This route will be responsible for validating the email address and sending the password reset request to the corresponding user:

```php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;

Route::post('/forgot-password', function (Request $request) {
    $request->validate(['email' => 'required|email']);

    $status = Password::sendResetLink(
        $request->only('email')
    );

    return $status === Password::ResetLinkSent
        ? back()->with(['status' => __($status)])
        : back()->withErrors(['email' => __($status)]);
})->middleware('guest')->name('password.email');
```

Before moving on, let's examine this route in more detail. First, the request's `email` attribute is validated. Next, we will use Laravel's built-in "password broker" (via the `Password` facade) to send a password reset link to the user. The password broker will take care of retrieving the user by the given field (in this case, the email address) and sending the user a password reset link via Laravel's built-in [notification system](/docs/{{version}}/notifications).

The `sendResetLink` method returns a "status" slug. This status may be translated using Laravel's [localization](/docs/{{version}}/localization) helpers in order to display a user-friendly message to the user regarding the status of their request. The translation of the password reset status is determined by your application's `lang/{lang}/passwords.php` language file. An entry for each possible value of the status slug is located within the `passwords` language file.

> [!NOTE]
> By default, the Laravel application skeleton does not include the `lang` directory. If you would like to customize Laravel's language files, you may publish them via the `lang:publish` Artisan command.

You may be wondering how Laravel knows how to retrieve the user record from your application's database when calling the `Password` facade's `sendResetLink` method. The Laravel password broker utilizes your authentication system's "user providers" to retrieve database records. The user provider used by the password broker is configured within the `passwords` configuration array of your `config/auth.php` configuration file. To learn more about writing custom user providers, consult the [authentication documentation](/docs/{{version}}/authentication#adding-custom-user-providers).

> [!NOTE]
> When manually implementing password resets, you are required to define the contents of the views and routes yourself. If you would like scaffolding that includes all necessary authentication and verification logic, check out the [Laravel application starter kits](/docs/{{version}}/starter-kits).

---

## Fortify Password Reset Customizing Password Resets
Fortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md

### Customizing Password Resets

The password reset process may be customized by modifying the `App\Actions\ResetUserPassword` action that was generated when you installed Laravel Fortify.

---

## Fortify Authentication Customizing User Authentication Authentication Guard
Fortify | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/fortify.md

#### Authentication Guard

You may customize the authentication guard used by Fortify within your application's `fortify` configuration file. However, you should ensure that the configured guard is an implementation of `Illuminate\Contracts\Auth\StatefulGuard`. If you are attempting to use Laravel Fortify to authenticate an SPA, you should use Laravel's default `web` guard in combination with [Laravel Sanctum](https://laravel.com/docs/sanctum).

---

## Passwords Routing Resetting the Password Handling the Form Submission
Passwords | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/passwords.md

#### Handling the Form Submission

Of course, we need to define a route to actually handle the password reset form submission. This route will be responsible for validating the incoming request and updating the user's password in the database:

```php
use App\Models\User;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;

Route::post('/reset-password', function (Request $request) {
    $request->validate([
        'token' => 'required',
        'email' => 'required|email',
        'password' => 'required|min:8|confirmed',
    ]);

    $status = Password::reset(
        $request->only('email', 'password', 'password_confirmation', 'token'),
        function (User $user, string $password) {
            $user->forceFill([
                'password' => Hash::make($password)
            ])->setRememberToken(Str::random(60));

            $user->save();

            event(new PasswordReset($user));
        }
    );

    return $status === Password::PasswordReset
        ? redirect()->route('login')->with('status', __($status))
        : back()->withErrors(['email' => [__($status)]]);
})->middleware('guest')->name('password.update');
```

Before moving on, let's examine this route in more detail. First, the request's `token`, `email`, and `password` attributes are validated. Next, we will use Laravel's built-in "password broker" (via the `Password` facade) to validate the password reset request credentials.

If the token, email address, and password given to the password broker are valid, the closure passed to the `reset` method will be invoked. Within this closure, which receives the user instance and the plain-text password provided to the password reset form, we may update the user's password in the database.

The `reset` method returns a "status" slug. This status may be translated using Laravel's [localization](/docs/{{version}}/localization) helpers in order to display a user-friendly message to the user regarding the status of their request. The translation of the password reset status is determined by your application's `lang/{lang}/passwords.php` language file. An entry for each possible value of the status slug is located within the `passwords` language file. If your application does not contain a `lang` directory, you may create it using the `lang:publish` Artisan command.

Before moving on, you may be wondering how Laravel knows how to retrieve the user record from your application's database when calling the `Password` facade's `reset` method. The Laravel password broker utilizes your authentication system's "user providers" to retrieve database records. The user provider used by the password broker is configured within the `passwords` configuration array of your `config/auth.php` configuration file. To learn more about writing custom user providers, consult the [authentication documentation](/docs/{{version}}/authentication#adding-custom-user-providers).

---

## Fortify Registration Customizing Registration
Fortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md

### Customizing Registration

The user validation and creation process may be customized by modifying the `App\Actions\Fortify\CreateNewUser` action that was generated when you installed Laravel Fortify.

---

## Passport Password Grant Customizing the User Provider
Passport | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/passport.md

### Customizing the User Provider

If your application uses more than one [authentication user provider](/docs/{{version}}/authentication#introduction), you may specify which user provider the password grant client uses by providing a `--provider` option when creating the client via the `artisan passport:client --password` command. The given provider name should match a valid provider defined in your application's `config/auth.php` configuration file. You can then [protect your route using middleware](#multiple-authentication-guards) to ensure that only users from the guard's specified provider are authorized.

---

## Fortify Authentication Customizing User Authentication
Fortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md

### Customizing User Authentication

Fortify will automatically retrieve and authenticate the user based on the provided credentials and the authentication guard that is configured for your application. However, you may sometimes wish to have full customization over how login credentials are authenticated and users are retrieved. Thankfully, Fortify allows you to easily accomplish this using the `Fortify::authenticateUsing` method.

This method accepts a closure which receives the incoming HTTP request. The closure is responsible for validating the login credentials attached to the request and returning the associated user instance. If the credentials are invalid or no user can be found, `null` or `false` should be returned by the closure. Typically, this method should be called from the `boot` method of your `FortifyServiceProvider`:

```php
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Laravel\Fortify\Fortify;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Fortify::authenticateUsing(function (Request $request) {
        $user = User::where('email', $request->email)->first();

        if ($user &&
            Hash::check($request->password, $user->password)) {
            return $user;
        }
    });

    // ...
}
```

---

## Fortify Authentication Customizing Redirects
Fortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md

### Customizing Redirects

If the login attempt is successful, Fortify will redirect you to the URI configured via the `home` configuration option within your application's `fortify` configuration file. If the login request was an XHR request, a 200 HTTP response will be returned. After a user logs out of the application, the user will be redirected to the `/` URI.

If you need advanced customization of this behavior, you may bind implementations of the `LoginResponse` and `LogoutResponse` contracts into the Laravel [service container](/docs/{{version}}/container). Typically, this should be done within the `register` method of your application's `App\Providers\FortifyServiceProvider` class:

```php
use Laravel\Fortify\Contracts\LogoutResponse;

/**
 * Register any application services.
 */
public function register(): void
{
    $this->app->instance(LogoutResponse::class, new class implements LogoutResponse {
        public function toResponse($request)
        {
            return redirect('/');
        }
    });
}
```

---

## Fortify Authentication Customizing the Authentication Pipeline
Fortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md

### Customizing the Authentication Pipeline

Laravel Fortify authenticates login requests through a pipeline of invokable classes. If you would like, you may define a custom pipeline of classes that login requests should be piped through. Each class should have an `__invoke` method which receives the incoming `Illuminate\Http\Request` instance and, like [middleware](/docs/{{version}}/middleware), a `$next` variable that is invoked in order to pass the request to the next class in the pipeline.

To define your custom pipeline, you may use the `Fortify::authenticateThrough` method. This method accepts a closure which should return the array of classes to pipe the login request through. Typically, this method should be called from the `boot` method of your `App\Providers\FortifyServiceProvider` class.

The example below contains the default pipeline definition that you may use as a starting point when making your own modifications:

```php
use Laravel\Fortify\Actions\AttemptToAuthenticate;
use Laravel\Fortify\Actions\CanonicalizeUsername;
use Laravel\Fortify\Actions\EnsureLoginIsNotThrottled;
use Laravel\Fortify\Actions\PrepareAuthenticatedSession;
use Laravel\Fortify\Actions\RedirectIfTwoFactorAuthenticatable;
use Laravel\Fortify\Features;
use Laravel\Fortify\Fortify;
use Illuminate\Http\Request;

Fortify::authenticateThrough(function (Request $request) {
    return array_filter([
            config('fortify.limiters.login') ? null : EnsureLoginIsNotThrottled::class,
            config('fortify.lowercase_usernames') ? CanonicalizeUsername::class : null,
            Features::enabled(Features::twoFactorAuthentication()) ? RedirectIfTwoFactorAuthenticatable::class : null,
            AttemptToAuthenticate::class,
            PrepareAuthenticatedSession::class,
    ]);
});
```

#### Authentication Throttling

By default, Fortify will throttle authentication attempts using the `EnsureLoginIsNotThrottled` middleware. This middleware throttles attempts that are unique to a username and IP address combination.

Some applications may require a different approach to throttling authentication attempts, such as throttling by IP address alone. Therefore, Fortify allows you to specify your own [rate limiter](/docs/{{version}}/routing#rate-limiting) via the `fortify.limiters.login` configuration option. Of course, this configuration option is located in your application's `config/fortify.php` configuration file.

> [!NOTE]
> Utilizing a mixture of throttling, [two-factor authentication](/docs/{{version}}/fortify#two-factor-authentication), and an external web application firewall (WAF) will provide the most robust defense for your legitimate application users.

---

## Fortify Password Confirmation
Fortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md

## Password Confirmation

While building your application, you may occasionally have actions that should require the user to confirm their password before the action is performed. Typically, these routes are protected by Laravel's built-in `password.confirm` middleware.

To begin implementing password confirmation functionality, we need to instruct Fortify how to return our application's "password confirmation" view. Remember, Fortify is a headless authentication library. If you would like a frontend implementation of Laravel's authentication features that are already completed for you, you should use an [application starter kit](/docs/{{version}}/starter-kits).

All of Fortify's view rendering logic may be customized using the appropriate methods available via the `Laravel\Fortify\Fortify` class. Typically, you should call this method from the `boot` method of your application's `App\Providers\FortifyServiceProvider` class:

```php
use Laravel\Fortify\Fortify;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Fortify::confirmPasswordView(function () {
        return view('auth.confirm-password');
    });

    // ...
}
```

Fortify will take care of defining the `/user/confirm-password` endpoint that returns this view. Your `confirm-password` template should include a form that makes a POST request to the `/user/confirm-password` endpoint. The `/user/confirm-password` endpoint expects a `password` field that contains the user's current password.

If the password matches the user's current password, Fortify will redirect the user to the route they were attempting to access. If the request was an XHR request, a 201 HTTP response will be returned.

If the request was not successful, the user will be redirected back to the confirm password screen and the validation errors will be available to you via the shared `$errors` Blade template variable. Or, in the case of an XHR request, the validation errors will be returned with a 422 HTTP response.

---

## Fortify Authentication Customizing User Authentication
Fortify | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/fortify.md

### Customizing User Authentication

Fortify will automatically retrieve and authenticate the user based on the provided credentials and the authentication guard that is configured for your application. However, you may sometimes wish to have full customization over how login credentials are authenticated and users are retrieved. Thankfully, Fortify allows you to easily accomplish this using the `Fortify::authenticateUsing` method.

This method accepts a closure which receives the incoming HTTP request. The closure is responsible for validating the login credentials attached to the request and returning the associated user instance. If the credentials are invalid or no user can be found, `null` or `false` should be returned by the closure. Typically, this method should be called from the `boot` method of your `FortifyServiceProvider`:

```php
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Laravel\Fortify\Fortify;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Fortify::authenticateUsing(function (Request $request) {
        $user = User::where('email', $request->email)->first();

        if ($user &&
            Hash::check($request->password, $user->password)) {
            return $user;
        }
    });

    // ...
}
```

---

## Fortify Authentication Customizing the Authentication Pipeline
Fortify | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/fortify.md

### Customizing the Authentication Pipeline

Laravel Fortify authenticates login requests through a pipeline of invokable classes. If you would like, you may define a custom pipeline of classes that login requests should be piped through. Each class should have an `__invoke` method which receives the incoming `Illuminate\Http\Request` instance and, like [middleware](/docs/{{version}}/middleware), a `$next` variable that is invoked in order to pass the request to the next class in the pipeline.

To define your custom pipeline, you may use the `Fortify::authenticateThrough` method. This method accepts a closure which should return the array of classes to pipe the login request through. Typically, this method should be called from the `boot` method of your `App\Providers\FortifyServiceProvider` class.

The example below contains the default pipeline definition that you may use as a starting point when making your own modifications:

```php
use Laravel\Fortify\Actions\AttemptToAuthenticate;
use Laravel\Fortify\Actions\CanonicalizeUsername;
use Laravel\Fortify\Actions\EnsureLoginIsNotThrottled;
use Laravel\Fortify\Actions\PrepareAuthenticatedSession;
use Laravel\Fortify\Actions\RedirectIfTwoFactorAuthenticatable;
use Laravel\Fortify\Features;
use Laravel\Fortify\Fortify;
use Illuminate\Http\Request;

Fortify::authenticateThrough(function (Request $request) {
    return array_filter([
            config('fortify.limiters.login') ? null : EnsureLoginIsNotThrottled::class,
            config('fortify.lowercase_usernames') ? CanonicalizeUsername::class : null,
            Features::enabled(Features::twoFactorAuthentication()) ? RedirectIfTwoFactorAuthenticatable::class : null,
            AttemptToAuthenticate::class,
            PrepareAuthenticatedSession::class,
    ]);
});
```

#### Authentication Throttling

By default, Fortify will throttle authentication attempts using the `EnsureLoginIsNotThrottled` middleware. This middleware throttles attempts that are unique to a username and IP address combination.

Some applications may require a different approach to throttling authentication attempts, such as throttling by IP address alone. Therefore, Fortify allows you to specify your own [rate limiter](/docs/{{version}}/routing#rate-limiting) via the `fortify.limiters.login` configuration option. Of course, this configuration option is located in your application's `config/fortify.php` configuration file.

> [!NOTE]
> Utilizing a mixture of throttling, [two-factor authentication](/docs/{{version}}/fortify#two-factor-authentication), and an external web application firewall (WAF) will provide the most robust defense for your legitimate application users.

---

## Passwords Routing Resetting the Password
Passwords | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/passwords.md

### Resetting the Password

---

## Passport Personal Access Tokens Customizing the User Provider
Passport | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/passport.md

### Customizing the User Provider

If your application uses more than one [authentication user provider](/docs/{{version}}/authentication#introduction), you may specify which user provider the personal access grant client uses by providing a `--provider` option when creating the client via the `artisan passport:client --personal` command. The given provider name should match a valid provider defined in your application's `config/auth.php` configuration file. You can then [protect your route using middleware](#multiple-authentication-guards) to ensure that only users from the guard's specified provider are authorized.

---

## Fortify Password Reset Resetting the Password
Fortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md

### Resetting the Password

To finish implementing our application's password reset functionality, we need to instruct Fortify how to return our "reset password" view.

All of Fortify's view rendering logic may be customized using the appropriate methods available via the `Laravel\Fortify\Fortify` class. Typically, you should call this method from the `boot` method of your application's `App\Providers\FortifyServiceProvider` class:

```php
use Laravel\Fortify\Fortify;
use Illuminate\Http\Request;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Fortify::resetPasswordView(function (Request $request) {
        return view('auth.reset-password', ['request' => $request]);
    });

    // ...
}
```

Fortify will take care of defining the route to display this view. Your `reset-password` template should include a form that makes a POST request to `/reset-password`.

The `/reset-password` endpoint expects a string `email` field, a `password` field, a `password_confirmation` field, and a hidden field named `token` that contains the value of `request()->route('token')`. The name of the "email" field / database column should match the `email` configuration value defined within your application's `fortify` configuration file.

---

## Authentication Authentication Quickstart Login Throttling
Authentication | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/authentication.md

### Login Throttling

If you are using one of our [application starter kits](/docs/{{version}}/starter-kits), rate limiting will automatically be applied to login attempts. By default, the user will not be able to login for one minute if they fail to provide the correct credentials after several attempts. The throttling is unique to the user's username / email address and their IP address.

> [!NOTE]
> If you would like to rate limit other routes in your application, check out the [rate limiting documentation](/docs/{{version}}/routing#rate-limiting).

---

## Fortify Password Reset Resetting the Password Handling the Password Reset Response
Fortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md

#### Handling the Password Reset Response

If the password reset request was successful, Fortify will redirect back to the `/login` route so that the user can log in with their new password. In addition, a `status` session variable will be set so that you may display the successful status of the reset on your login screen:

```blade
@if (session('status'))
    <div class="mb-4 font-medium text-sm text-green-600">
        {{ session('status') }}
    </div>
@endif
```

If the request was an XHR request, a 200 HTTP response will be returned.

If the request was not successful, the user will be redirected back to the reset password screen and the validation errors will be available to you via the shared `$errors` [Blade template variable](/docs/{{version}}/validation#quick-displaying-the-validation-errors). Or, in the case of an XHR request, the validation errors will be returned with a 422 HTTP response.

---

## Session Adding Custom Session Drivers
Session | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/session.md

## Adding Custom Session Drivers

---

## Fortify Password Reset Requesting a Password Reset Link Handling the Password Reset Link Request Response
Fortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md

#### Handling the Password Reset Link Request Response

If the password reset link request was successful, Fortify will redirect the user back to the `/forgot-password` endpoint and send an email to the user with a secure link they can use to reset their password. If the request was an XHR request, a 200 HTTP response will be returned.

After being redirected back to the `/forgot-password` endpoint after a successful request, the `status` session variable may be used to display the status of the password reset link request attempt.

The value of the `$status` session variable will match one of the translation strings defined within your application's `passwords` [language file](/docs/{{version}}/localization). If you would like to customize this value and have not published Laravel's language files, you may do so via the `lang:publish` Artisan command:

```html
@if (session('status'))
    <div class="mb-4 font-medium text-sm text-green-600">
        {{ session('status') }}
    </div>
@endif
```

If the request was not successful, the user will be redirected back to the request password reset link screen and the validation errors will be available to you via the shared `$errors` [Blade template variable](/docs/{{version}}/validation#quick-displaying-the-validation-errors). Or, in the case of an XHR request, the validation errors will be returned with a 422 HTTP response.

---

## Vite Advanced Customization Correcting Dev Server URLs
Vite | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/vite.md

### Correcting Dev Server URLs

Some plugins within the Vite ecosystem assume that URLs which begin with a forward-slash will always point to the Vite dev server. However, due to the nature of the Laravel integration, this is not the case.

For example, the `vite-imagetools` plugin outputs URLs like the following while Vite is serving your assets:

```html
<img src="/@imagetools/f0b2f404b13f052c604e632f2fb60381bf61a520">
```

The `vite-imagetools` plugin is expecting that the output URL will be intercepted by Vite and the plugin may then handle all URLs that start with `/@imagetools`. If you are using plugins that are expecting this behavior, you will need to manually correct the URLs. You can do this in your `vite.config.js` file by using the `transformOnServe` option.

In this particular example, we will prepend the dev server URL to all occurrences of `/@imagetools` within the generated code:

```js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import { imagetools } from 'vite-imagetools';

export default defineConfig({
    plugins: [
        laravel({
            // ...
            transformOnServe: (code, devServerUrl) => code.replaceAll('/@imagetools', devServerUrl+'/@imagetools'),
        }),
        imagetools(),
    ],
});
```

Now, while Vite is serving Assets, it will output URLs that point to the Vite dev server:

```html
- <img src="/@imagetools/f0b2f404b13f052c604e632f2fb60381bf61a520"><!-- [tl! remove] -->
+ <img src="http://[::1]:5173/@imagetools/f0b2f404b13f052c604e632f2fb60381bf61a520"><!-- [tl! add] -->
```

---

## Fortify Password Reset Requesting a Password Reset Link
Fortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md

### Requesting a Password Reset Link

To begin implementing our application's password reset functionality, we need to instruct Fortify how to return our "forgot password" view. Remember, Fortify is a headless authentication library. If you would like a frontend implementation of Laravel's authentication features that are already completed for you, you should use an [application starter kit](/docs/{{version}}/starter-kits).

All of Fortify's view rendering logic may be customized using the appropriate methods available via the `Laravel\Fortify\Fortify` class. Typically, you should call this method from the `boot` method of your application's `App\Providers\FortifyServiceProvider` class:

```php
use Laravel\Fortify\Fortify;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Fortify::requestPasswordResetLinkView(function () {
        return view('auth.forgot-password');
    });

    // ...
}
```

Fortify will take care of defining the `/forgot-password` endpoint that returns this view. Your `forgot-password` template should include a form that makes a POST request to the `/forgot-password` endpoint.

The `/forgot-password` endpoint expects a string `email` field. The name of this field / database column should match the `email` configuration value within your application's `fortify` configuration file.

---

## Passwords Customization
Passwords | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/passwords.md

## Customization

---

## Passwords
Passwords | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/passwords.md

# Resetting Passwords

- [Introduction](#introduction)
    - [Configuration](#configuration)
    - [Driver Prerequisites](#driver-prerequisites)
    - [Model Preparation](#model-preparation)
    - [Configuring Trusted Hosts](#configuring-trusted-hosts)
- [Routing](#routing)
    - [Requesting the Password Reset Link](#requesting-the-password-reset-link)
    - [Resetting the Password](#resetting-the-password)
- [Deleting Expired Tokens](#deleting-expired-tokens)
- [Customization](#password-customization)

---

## Vite Advanced Customization Dev Server Cross-Origin Resource Sharing (CORS)
Vite | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/vite.md

### Dev Server Cross-Origin Resource Sharing (CORS)

If you are experiencing Cross-Origin Resource Sharing (CORS) issues in the browser while fetching assets from the Vite dev server, you may need to grant your custom origin access to the dev server. Vite combined with the Laravel plugin allows the following origins without any additional configuration:

- `::1`
- `127.0.0.1`
- `localhost`
- `*.test`
- `*.localhost`
- `APP_URL` in the project's `.env`

The easiest way to allow a custom origin for your project is to ensure that your application's `APP_URL` environment variable matches the origin you are visiting in your browser. For example, if you visiting `https://my-app.laravel`, you should update your `.env` to match:

```env
APP_URL=https://my-app.laravel
```

If you need more fine-grained control over the origins, such as supporting multiple origins, you should utilize [Vite's comprehensive and flexible built-in CORS server configuration](https://vite.dev/config/server-options.html#server-cors). For example, you may specify multiple origins in the `server.cors.origin` configuration option in the project's `vite.config.js` file:

```js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            input: 'resources/js/app.js',
            refresh: true,
        }),
    ],
    server: {  // [tl! add]
        cors: {  // [tl! add]
            origin: [  // [tl! add]
                'https://backend.laravel',  // [tl! add]
                'http://admin.laravel:8566',  // [tl! add]
            ],  // [tl! add]
        },  // [tl! add]
    },  // [tl! add]
});
```

You may also include regex patterns, which can be helpful if you would like to allow all origins for a given top-level domain, such as `*.laravel`:

```js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            input: 'resources/js/app.js',
            refresh: true,
        }),
    ],
    server: {  // [tl! add]
        cors: {  // [tl! add]
            origin: [ // [tl! add]
                // Supports: SCHEME://DOMAIN.laravel[:PORT] [tl! add]
                /^https?:\/\/.*\.laravel(:\d+)?$/, //[tl! add]
            ], // [tl! add]
        }, // [tl! add]
    }, // [tl! add]
});
```

---

## Fortify Installation Disabling Views Disabling Views and Password Reset
Fortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md

#### Disabling Views and Password Reset

If you choose to disable Fortify's views and you will be implementing password reset features for your application, you should still define a route named `password.reset` that is responsible for displaying your application's "reset password" view. This is necessary because Laravel's `Illuminate\Auth\Notifications\ResetPassword` notification will generate the password reset URL via the `password.reset` named route.

---

## Vite Advanced Customization
Vite | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/vite.md

## Advanced Customization

Out of the box, Laravel's Vite plugin uses sensible conventions that should work for the majority of applications; however, sometimes you may need to customize Vite's behavior. To enable additional customization options, we offer the following methods and options which can be used in place of the `@vite` Blade directive:

```blade
<!doctype html>
<head>
    {{-- ... --}}

    {{
        Vite::useHotFile(storage_path('vite.hot')) // Customize the "hot" file...
            ->useBuildDirectory('bundle') // Customize the build directory...
            ->useManifestFilename('assets.json') // Customize the manifest filename...
            ->withEntryPoints(['resources/js/app.js']) // Specify the entry points...
            ->createAssetPathsUsing(function (string $path, ?bool $secure) { // Customize the backend path generation for built assets...
                return "https://cdn.example.com/{$path}";
            })
    }}
</head>
```

Within the `vite.config.js` file, you should then specify the same configuration:

```js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            hotFile: 'storage/vite.hot', // Customize the "hot" file...
            buildDirectory: 'bundle', // Customize the build directory...
            input: ['resources/js/app.js'], // Specify the entry points...
        }),
    ],
    build: {
      manifest: 'assets.json', // Customize the manifest filename...
    },
});
```

---

## Validation Validating Passwords Defining Default Password Rules
Validation | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/validation.md

#### Defining Default Password Rules

You may find it convenient to specify the default validation rules for passwords in a single location of your application. You can easily accomplish this using the `Password::defaults` method, which accepts a closure. The closure given to the `defaults` method should return the default configuration of the Password rule. Typically, the `defaults` rule should be called within the `boot` method of one of your application's service providers:

```php
use Illuminate\Validation\Rules\Password;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Password::defaults(function () {
        $rule = Password::min(8);

        return $this->app->isProduction()
            ? $rule->mixedCase()->uncompromised()
            : $rule;
    });
}
```

Then, when you would like to apply the default rules to a particular password undergoing validation, you may invoke the `defaults` method with no arguments:

```php
'password' => ['required', Password::defaults()],
```

Occasionally, you may want to attach additional validation rules to your default password validation rules. You may use the `rules` method to accomplish this:

```php
use App\Rules\ZxcvbnRule;

Password::defaults(function () {
    $rule = Password::min(8)->rules([new ZxcvbnRule]);

    // ...
});
```

---

## Vite Custom Base URLs
Vite | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/vite.md

## Custom Base URLs

If your Vite compiled assets are deployed to a domain separate from your application, such as via a CDN, you must specify the `ASSET_URL` environment variable within your application's `.env` file:

```env
ASSET_URL=https://cdn.example.com
```

After configuring the asset URL, all re-written URLs to your assets will be prefixed with the configured value:

```text
https://cdn.example.com/build/assets/app.9dce8d17.js
```

Remember that [absolute URLs are not re-written by Vite](#url-processing), so they will not be prefixed.

---

## Validation Validating Passwords
Validation | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/validation.md

## Validating Passwords

To ensure that passwords have an adequate level of complexity, you may use Laravel's `Password` rule object:

```php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rules\Password;

$validator = Validator::make($request->all(), [
    'password' => ['required', 'confirmed', Password::min(8)],
]);
```

The `Password` rule object allows you to easily customize the password complexity requirements for your application, such as specifying that passwords require at least one letter, number, symbol, or characters with mixed casing:

```php
// Require at least 8 characters...
Password::min(8)

// Require at least one letter...
Password::min(8)->letters()

// Require at least one uppercase and one lowercase letter...
Password::min(8)->mixedCase()

// Require at least one number...
Password::min(8)->numbers()

// Require at least one symbol...
Password::min(8)->symbols()
```

In addition, you may ensure that a password has not been compromised in a public password data breach leak using the `uncompromised` method:

```php
Password::min(8)->uncompromised()
```

Internally, the `Password` rule object uses the [k-Anonymity](https://en.wikipedia.org/wiki/K-anonymity) model to determine if a password has been leaked via the [haveibeenpwned.com](https://haveibeenpwned.com) service without sacrificing the user's privacy or security.

By default, if a password appears at least once in a data leak, it will be considered compromised. You can customize this threshold using the first argument of the `uncompromised` method:

```php
// Ensure the password appears less than 3 times in the same data leak...
Password::min(8)->uncompromised(3);
```

Of course, you may chain all the methods in the examples above:

```php
Password::min(8)
    ->letters()
    ->mixedCase()
    ->numbers()
    ->symbols()
    ->uncompromised()
```

_[Truncated]_


Output:
Wall time: 3.7870 seconds
Output:
[{"type":"text","text":"# Search Results\n\n## Fortify Authentication Customizing User Authentication Authentication Guard\nFortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md\n\n\n#### Authentication Guard\n\nYou may customize the authentication guard used by Fortify within your application's `fortify` configuration file. However, you should ensure that the configured guard is an implementation of `Illuminate\\Contracts\\Auth\\StatefulGuard`. If you are attempting to use Laravel Fortify to authenticate an SPA, you should use Laravel's default `web` guard in combination with [Laravel Sanctum](https://laravel.com/docs/sanctum).\n\n---\n\n## Passwords Routing Requesting the Password Reset Link Handling the Form Submission\nPasswords | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/passwords.md\n\n\n#### Handling the Form Submission\n\nNext, we will define a route that handles the form submission request from the \"forgot password\" view. This route will be responsible for validating the email address and sending the password reset request to the corresponding user:\n\n```php\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Password;\n\nRoute::post('/forgot-password', function (Request $request) {\n    $request->validate(['email' => 'required|email']);\n\n    $status = Password::sendResetLink(\n        $request->only('email')\n    );\n\n    return $status === Password::ResetLinkSent\n        ? back()->with(['status' => __($status)])\n        : back()->withErrors(['email' => __($status)]);\n})->middleware('guest')->name('password.email');\n```\n\nBefore moving on, let's examine this route in more detail. First, the request's `email` attribute is validated. Next, we will use Laravel's built-in \"password broker\" (via the `Password` facade) to send a password reset link to the user. The password broker will take care of retrieving the user by the given field (in this case, the email address) and sending the user a password reset link via Laravel's built-in [notification system](/docs/{{version}}/notifications).\n\nThe `sendResetLink` method returns a \"status\" slug. This status may be translated using Laravel's [localization](/docs/{{version}}/localization) helpers in order to display a user-friendly message to the user regarding the status of their request. The translation of the password reset status is determined by your application's `lang/{lang}/passwords.php` language file. An entry for each possible value of the status slug is located within the `passwords` language file.\n\n> [!NOTE]\n> By default, the Laravel application skeleton does not include the `lang` directory. If you would like to customize Laravel's language files, you may publish them via the `lang:publish` Artisan command.\n\nYou may be wondering how Laravel knows how to retrieve the user record from your application's database when calling the `Password` facade's `sendResetLink` method. The Laravel password broker utilizes your authentication system's \"user providers\" to retrieve database records. The user provider used by the password broker is configured within the `passwords` configuration array of your `config/auth.php` configuration file. To learn more about writing custom user providers, consult the [authentication documentation](/docs/{{version}}/authentication#adding-custom-user-providers).\n\n> [!NOTE]\n> When manually implementing password resets, you are required to define the contents of the views and routes yourself. If you would like scaffolding that includes all necessary authentication and verification logic, check out the [Laravel application starter kits](/docs/{{version}}/starter-kits).\n\n---\n\n## Fortify Password Reset Customizing Password Resets\nFortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md\n\n\n### Customizing Password Resets\n\nThe password reset process may be customized by modifying the `App\\Actions\\ResetUserPassword` action that was generated when you installed Laravel Fortify.\n\n---\n\n## Fortify Authentication Customizing User Authentication Authentication Guard\nFortify | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/fortify.md\n\n\n#### Authentication Guard\n\nYou may customize the authentication guard used by Fortify within your application's `fortify` configuration file. However, you should ensure that the configured guard is an implementation of `Illuminate\\Contracts\\Auth\\StatefulGuard`. If you are attempting to use Laravel Fortify to authenticate an SPA, you should use Laravel's default `web` guard in combination with [Laravel Sanctum](https://laravel.com/docs/sanctum).\n\n---\n\n## Passwords Routing Resetting the Password Handling the Form Submission\nPasswords | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/passwords.md\n\n\n#### Handling the Form Submission\n\nOf course, we need to define a route to actually handle the password reset form submission. This route will be responsible for validating the incoming request and updating the user's password in the database:\n\n```php\nuse App\\Models\\User;\nuse Illuminate\\Auth\\Events\\PasswordReset;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Hash;\nuse Illuminate\\Support\\Facades\\Password;\nuse Illuminate\\Support\\Str;\n\nRoute::post('/reset-password', function (Request $request) {\n    $request->validate([\n        'token' => 'required',\n        'email' => 'required|email',\n        'password' => 'required|min:8|confirmed',\n    ]);\n\n    $status = Password::reset(\n        $request->only('email', 'password', 'password_confirmation', 'token'),\n        function (User $user, string $password) {\n            $user->forceFill([\n                'password' => Hash::make($password)\n            ])->setRememberToken(Str::random(60));\n\n            $user->save();\n\n            event(new PasswordReset($user));\n        }\n    );\n\n    return $status === Password::PasswordReset\n        ? redirect()->route('login')->with('status', __($status))\n        : back()->withErrors(['email' => [__($status)]]);\n})->middleware('guest')->name('password.update');\n```\n\nBefore moving on, let's examine this route in more detail. First, the request's `token`, `email`, and `password` attributes are validated. Next, we will use Laravel's built-in \"password broker\" (via the `Password` facade) to validate the password reset request credentials.\n\nIf the token, email address, and password given to the password broker are valid, the closure passed to the `reset` method will be invoked. Within this closure, which receives the user instance and the plain-text password provided to the password reset form, we may update the user's password in the database.\n\nThe `reset` method returns a \"status\" slug. This status may be translated using Laravel's [localization](/docs/{{version}}/localization) helpers in order to display a user-friendly message to the user regarding the status of their request. The translation of the password reset status is determined by your application's `lang/{lang}/passwords.php` language file. An entry for each possible value of the status slug is located within the `passwords` language file. If your application does not contain a `lang` directory, you may create it using the `lang:publish` Artisan command.\n\nBefore moving on, you may be wondering how Laravel knows how to retrieve the user record from your application's database when calling the `Password` facade's `reset` method. The Laravel password broker utilizes your authentication system's \"user providers\" to retrieve database records. The user provider used by the password broker is configured within the `passwords` configuration array of your `config/auth.php` configuration file. To learn more about writing custom user providers, consult the [authentication documentation](/docs/{{version}}/authentication#adding-custom-user-providers).\n\n---\n\n## Fortify Registration Customizing Registration\nFortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md\n\n\n### Customizing Registration\n\nThe user validation and creation process may be customized by modifying the `App\\Actions\\Fortify\\CreateNewUser` action that was generated when you installed Laravel Fortify.\n\n---\n\n## Passport Password Grant Customizing the User Provider\nPassport | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/passport.md\n\n\n### Customizing the User Provider\n\nIf your application uses more than one [authentication user provider](/docs/{{version}}/authentication#introduction), you may specify which user provider the password grant client uses by providing a `--provider` option when creating the client via the `artisan passport:client --password` command. The given provider name should match a valid provider defined in your application's `config/auth.php` configuration file. You can then [protect your route using middleware](#multiple-authentication-guards) to ensure that only users from the guard's specified provider are authorized.\n\n---\n\n## Fortify Authentication Customizing User Authentication\nFortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md\n\n\n### Customizing User Authentication\n\nFortify will automatically retrieve and authenticate the user based on the provided credentials and the authentication guard that is configured for your application. However, you may sometimes wish to have full customization over how login credentials are authenticated and users are retrieved. Thankfully, Fortify allows you to easily accomplish this using the `Fortify::authenticateUsing` method.\n\nThis method accepts a closure which receives the incoming HTTP request. The closure is responsible for validating the login credentials attached to the request and returning the associated user instance. If the credentials are invalid or no user can be found, `null` or `false` should be returned by the closure. Typically, this method should be called from the `boot` method of your `FortifyServiceProvider`:\n\n```php\nuse App\\Models\\User;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Hash;\nuse Laravel\\Fortify\\Fortify;\n\n/**\n * Bootstrap any application services.\n */\npublic function boot(): void\n{\n    Fortify::authenticateUsing(function (Request $request) {\n        $user = User::where('email', $request->email)->first();\n\n        if ($user &&\n            Hash::check($request->password, $user->password)) {\n            return $user;\n        }\n    });\n\n    // ...\n}\n```\n\n---\n\n## Fortify Authentication Customizing Redirects\nFortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md\n\n\n### Customizing Redirects\n\nIf the login attempt is successful, Fortify will redirect you to the URI configured via the `home` configuration option within your application's `fortify` configuration file. If the login request was an XHR request, a 200 HTTP response will be returned. After a user logs out of the application, the user will be redirected to the `/` URI.\n\nIf you need advanced customization of this behavior, you may bind implementations of the `LoginResponse` and `LogoutResponse` contracts into the Laravel [service container](/docs/{{version}}/container). Typically, this should be done within the `register` method of your application's `App\\Providers\\FortifyServiceProvider` class:\n\n```php\nuse Laravel\\Fortify\\Contracts\\LogoutResponse;\n\n/**\n * Register any application services.\n */\npublic function register(): void\n{\n    $this->app->instance(LogoutResponse::class, new class implements LogoutResponse {\n        public function toResponse($request)\n        {\n            return redirect('/');\n        }\n    });\n}\n```\n\n---\n\n## Fortify Authentication Customizing the Authentication Pipeline\nFortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md\n\n\n### Customizing the Authentication Pipeline\n\nLaravel Fortify authenticates login requests through a pipeline of invokable classes. If you would like, you may define a custom pipeline of classes that login requests should be piped through. Each class should have an `__invoke` method which receives the incoming `Illuminate\\Http\\Request` instance and, like [middleware](/docs/{{version}}/middleware), a `$next` variable that is invoked in order to pass the request to the next class in the pipeline.\n\nTo define your custom pipeline, you may use the `Fortify::authenticateThrough` method. This method accepts a closure which should return the array of classes to pipe the login request through. Typically, this method should be called from the `boot` method of your `App\\Providers\\FortifyServiceProvider` class.\n\nThe example below contains the default pipeline definition that you may use as a starting point when making your own modifications:\n\n```php\nuse Laravel\\Fortify\\Actions\\AttemptToAuthenticate;\nuse Laravel\\Fortify\\Actions\\CanonicalizeUsername;\nuse Laravel\\Fortify\\Actions\\EnsureLoginIsNotThrottled;\nuse Laravel\\Fortify\\Actions\\PrepareAuthenticatedSession;\nuse Laravel\\Fortify\\Actions\\RedirectIfTwoFactorAuthenticatable;\nuse Laravel\\Fortify\\Features;\nuse Laravel\\Fortify\\Fortify;\nuse Illuminate\\Http\\Request;\n\nFortify::authenticateThrough(function (Request $request) {\n    return array_filter([\n            config('fortify.limiters.login') ? null : EnsureLoginIsNotThrottled::class,\n            config('fortify.lowercase_usernames') ? CanonicalizeUsername::class : null,\n            Features::enabled(Features::twoFactorAuthentication()) ? RedirectIfTwoFactorAuthenticatable::class : null,\n            AttemptToAuthenticate::class,\n            PrepareAuthenticatedSession::class,\n    ]);\n});\n```\n\n#### Authentication Throttling\n\nBy default, Fortify will throttle authentication attempts using the `EnsureLoginIsNotThrottled` middleware. This middleware throttles attempts that are unique to a username and IP address combination.\n\nSome applications may require a different approach to throttling authentication attempts, such as throttling by IP address alone. Therefore, Fortify allows you to specify your own [rate limiter](/docs/{{version}}/routing#rate-limiting) via the `fortify.limiters.login` configuration option. Of course, this configuration option is located in your application's `config/fortify.php` configuration file.\n\n> [!NOTE]\n> Utilizing a mixture of throttling, [two-factor authentication](/docs/{{version}}/fortify#two-factor-authentication), and an external web application firewall (WAF) will provide the most robust defense for your legitimate application users.\n\n---\n\n## Fortify Password Confirmation\nFortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md\n\n\n## Password Confirmation\n\nWhile building your application, you may occasionally have actions that should require the user to confirm their password before the action is performed. Typically, these routes are protected by Laravel's built-in `password.confirm` middleware.\n\nTo begin implementing password confirmation functionality, we need to instruct Fortify how to return our application's \"password confirmation\" view. Remember, Fortify is a headless authentication library. If you would like a frontend implementation of Laravel's authentication features that are already completed for you, you should use an [application starter kit](/docs/{{version}}/starter-kits).\n\nAll of Fortify's view rendering logic may be customized using the appropriate methods available via the `Laravel\\Fortify\\Fortify` class. Typically, you should call this method from the `boot` method of your application's `App\\Providers\\FortifyServiceProvider` class:\n\n```php\nuse Laravel\\Fortify\\Fortify;\n\n/**\n * Bootstrap any application services.\n */\npublic function boot(): void\n{\n    Fortify::confirmPasswordView(function () {\n        return view('auth.confirm-password');\n    });\n\n    // ...\n}\n```\n\nFortify will take care of defining the `/user/confirm-password` endpoint that returns this view. Your `confirm-password` template should include a form that makes a POST request to the `/user/confirm-password` endpoint. The `/user/confirm-password` endpoint expects a `password` field that contains the user's current password.\n\nIf the password matches the user's current password, Fortify will redirect the user to the route they were attempting to access. If the request was an XHR request, a 201 HTTP response will be returned.\n\nIf the request was not successful, the user will be redirected back to the confirm password screen and the validation errors will be available to you via the shared `$errors` Blade template variable. Or, in the case of an XHR request, the validation errors will be returned with a 422 HTTP response.\n\n---\n\n## Fortify Authentication Customizing User Authentication\nFortify | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/fortify.md\n\n\n### Customizing User Authentication\n\nFortify will automatically retrieve and authenticate the user based on the provided credentials and the authentication guard that is configured for your application. However, you may sometimes wish to have full customization over how login credentials are authenticated and users are retrieved. Thankfully, Fortify allows you to easily accomplish this using the `Fortify::authenticateUsing` method.\n\nThis method accepts a closure which receives the incoming HTTP request. The closure is responsible for validating the login credentials attached to the request and returning the associated user instance. If the credentials are invalid or no user can be found, `null` or `false` should be returned by the closure. Typically, this method should be called from the `boot` method of your `FortifyServiceProvider`:\n\n```php\nuse App\\Models\\User;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Hash;\nuse Laravel\\Fortify\\Fortify;\n\n/**\n * Bootstrap any application services.\n */\npublic function boot(): void\n{\n    Fortify::authenticateUsing(function (Request $request) {\n        $user = User::where('email', $request->email)->first();\n\n        if ($user &&\n            Hash::check($request->password, $user->password)) {\n            return $user;\n        }\n    });\n\n    // ...\n}\n```\n\n---\n\n## Fortify Authentication Customizing the Authentication Pipeline\nFortify | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/fortify.md\n\n\n### Customizing the Authentication Pipeline\n\nLaravel Fortify authenticates login requests through a pipeline of invokable classes. If you would like, you may define a custom pipeline of classes that login requests should be piped through. Each class should have an `__invoke` method which receives the incoming `Illuminate\\Http\\Request` instance and, like [middleware](/docs/{{version}}/middleware), a `$next` variable that is invoked in order to pass the request to the next class in the pipeline.\n\nTo define your custom pipeline, you may use the `Fortify::authenticateThrough` method. This method accepts a closure which should return the array of classes to pipe the login request through. Typically, this method should be called from the `boot` method of your `App\\Providers\\FortifyServiceProvider` class.\n\nThe example below contains the default pipeline definition that you may use as a starting point when making your own modifications:\n\n```php\nuse Laravel\\Fortify\\Actions\\AttemptToAuthenticate;\nuse Laravel\\Fortify\\Actions\\CanonicalizeUsername;\nuse Laravel\\Fortify\\Actions\\EnsureLoginIsNotThrottled;\nuse Laravel\\Fortify\\Actions\\PrepareAuthenticatedSession;\nuse Laravel\\Fortify\\Actions\\RedirectIfTwoFactorAuthenticatable;\nuse Laravel\\Fortify\\Features;\nuse Laravel\\Fortify\\Fortify;\nuse Illuminate\\Http\\Request;\n\nFortify::authenticateThrough(function (Request $request) {\n    return array_filter([\n            config('fortify.limiters.login') ? null : EnsureLoginIsNotThrottled::class,\n            config('fortify.lowercase_usernames') ? CanonicalizeUsername::class : null,\n            Features::enabled(Features::twoFactorAuthentication()) ? RedirectIfTwoFactorAuthenticatable::class : null,\n            AttemptToAuthenticate::class,\n            PrepareAuthenticatedSession::class,\n    ]);\n});\n```\n\n#### Authentication Throttling\n\nBy default, Fortify will throttle authentication attempts using the `EnsureLoginIsNotThrottled` middleware. This middleware throttles attempts that are unique to a username and IP address combination.\n\nSome applications may require a different approach to throttling authentication attempts, such as throttling by IP address alone. Therefore, Fortify allows you to specify your own [rate limiter](/docs/{{version}}/routing#rate-limiting) via the `fortify.limiters.login` configuration option. Of course, this configuration option is located in your application's `config/fortify.php` configuration file.\n\n> [!NOTE]\n> Utilizing a mixture of throttling, [two-factor authentication](/docs/{{version}}/fortify#two-factor-authentication), and an external web application firewall (WAF) will provide the most robust defense for your legitimate application users.\n\n---\n\n## Passwords Routing Resetting the Password\nPasswords | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/passwords.md\n\n\n### Resetting the Password\n\n---\n\n## Passport Personal Access Tokens Customizing the User Provider\nPassport | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/passport.md\n\n\n### Customizing the User Provider\n\nIf your application uses more than one [authentication user provider](/docs/{{version}}/authentication#introduction), you may specify which user provider the personal access grant client uses by providing a `--provider` option when creating the client via the `artisan passport:client --personal` command. The given provider name should match a valid provider defined in your application's `config/auth.php` configuration file. You can then [protect your route using middleware](#multiple-authentication-guards) to ensure that only users from the guard's specified provider are authorized.\n\n---\n\n## Fortify Password Reset Resetting the Password\nFortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md\n\n\n### Resetting the Password\n\nTo finish implementing our application's password reset functionality, we need to instruct Fortify how to return our \"reset password\" view.\n\nAll of Fortify's view rendering logic may be customized using the appropriate methods available via the `Laravel\\Fortify\\Fortify` class. Typically, you should call this method from the `boot` method of your application's `App\\Providers\\FortifyServiceProvider` class:\n\n```php\nuse Laravel\\Fortify\\Fortify;\nuse Illuminate\\Http\\Request;\n\n/**\n * Bootstrap any application services.\n */\npublic function boot(): void\n{\n    Fortify::resetPasswordView(function (Request $request) {\n        return view('auth.reset-password', ['request' => $request]);\n    });\n\n    // ...\n}\n```\n\nFortify will take care of defining the route to display this view. Your `reset-password` template should include a form that makes a POST request to `/reset-password`.\n\nThe `/reset-password` endpoint expects a string `email` field, a `password` field, a `password_confirmation` field, and a hidden field named `token` that contains the value of `request()->route('token')`. The name of the \"email\" field / database column should match the `email` configuration value defined within your application's `fortify` configuration file.\n\n---\n\n## Authentication Authentication Quickstart Login Throttling\nAuthentication | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/authentication.md\n\n\n### Login Throttling\n\nIf you are using one of our [application starter kits](/docs/{{version}}/starter-kits), rate limiting will automatically be applied to login attempts. By default, the user will not be able to login for one minute if they fail to provide the correct credentials after several attempts. The throttling is unique to the user's username / email address and their IP address.\n\n> [!NOTE]\n> If you would like to rate limit other routes in your application, check out the [rate limiting documentation](/docs/{{version}}/routing#rate-limiting).\n\n---\n\n## Fortify Password Reset Resetting the Password Handling the Password Reset Response\nFortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md\n\n\n#### Handling the Password Reset Response\n\nIf the password reset request was successful, Fortify will redirect back to the `/login` route so that the user can log in with their new password. In addition, a `status` session variable will be set so that you may display the successful status of the reset on your login screen:\n\n```blade\n@if (session('status'))\n    <div class=\"mb-4 font-medium text-sm text-green-600\">\n        {{ session('status') }}\n    </div>\n@endif\n```\n\nIf the request was an XHR request, a 200 HTTP response will be returned.\n\nIf the request was not successful, the user will be redirected back to the reset password screen and the validation errors will be available to you via the shared `$errors` [Blade template variable](/docs/{{version}}/validation#quick-displaying-the-validation-errors). Or, in the case of an XHR request, the validation errors will be returned with a 422 HTTP response.\n\n---\n\n## Session Adding Custom Session Drivers\nSession | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/session.md\n\n\n## Adding Custom Session Drivers\n\n---\n\n## Fortify Password Reset Requesting a Password Reset Link Handling the Password Reset Link Request Response\nFortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md\n\n\n#### Handling the Password Reset Link Request Response\n\nIf the password reset link request was successful, Fortify will redirect the user back to the `/forgot-password` endpoint and send an email to the user with a secure link they can use to reset their password. If the request was an XHR request, a 200 HTTP response will be returned.\n\nAfter being redirected back to the `/forgot-password` endpoint after a successful request, the `status` session variable may be used to display the status of the password reset link request attempt.\n\nThe value of the `$status` session variable will match one of the translation strings defined within your application's `passwords` [language file](/docs/{{version}}/localization). If you would like to customize this value and have not published Laravel's language files, you may do so via the `lang:publish` Artisan command:\n\n```html\n@if (session('status'))\n    <div class=\"mb-4 font-medium text-sm text-green-600\">\n        {{ session('status') }}\n    </div>\n@endif\n```\n\nIf the request was not successful, the user will be redirected back to the request password reset link screen and the validation errors will be available to you via the shared `$errors` [Blade template variable](/docs/{{version}}/validation#quick-displaying-the-validation-errors). Or, in the case of an XHR request, the validation errors will be returned with a 422 HTTP response.\n\n---\n\n## Vite Advanced Customization Correcting Dev Server URLs\nVite | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/vite.md\n\n\n### Correcting Dev Server URLs\n\nSome plugins within the Vite ecosystem assume that URLs which begin with a forward-slash will always point to the Vite dev server. However, due to the nature of the Laravel integration, this is not the case.\n\nFor example, the `vite-imagetools` plugin outputs URLs like the following while Vite is serving your assets:\n\n```html\n<img src=\"/@imagetools/f0b2f404b13f052c604e632f2fb60381bf61a520\">\n```\n\nThe `vite-imagetools` plugin is expecting that the output URL will be intercepted by Vite and the plugin may then handle all URLs that start with `/@imagetools`. If you are using plugins that are expecting this behavior, you will need to manually correct the URLs. You can do this in your `vite.config.js` file by using the `transformOnServe` option.\n\nIn this particular example, we will prepend the dev server URL to all occurrences of `/@imagetools` within the generated code:\n\n```js\nimport { defineConfig } from 'vite';\nimport laravel from 'laravel-vite-plugin';\nimport { imagetools } from 'vite-imagetools';\n\nexport default defineConfig({\n    plugins: [\n        laravel({\n            // ...\n            transformOnServe: (code, devServerUrl) => code.replaceAll('/@imagetools', devServerUrl+'/@imagetools'),\n        }),\n        imagetools(),\n    ],\n});\n```\n\nNow, while Vite is serving Assets, it will output URLs that point to the Vite dev server:\n\n```html\n- <img src=\"/@imagetools/f0b2f404b13f052c604e632f2fb60381bf61a520\"><!-- [tl! remove] -->\n+ <img src=\"http://[::1]:5173/@imagetools/f0b2f404b13f052c604e632f2fb60381bf61a520\"><!-- [tl! add] -->\n```\n\n---\n\n## Fortify Password Reset Requesting a Password Reset Link\nFortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md\n\n\n### Requesting a Password Reset Link\n\nTo begin implementing our application's password reset functionality, we need to instruct Fortify how to return our \"forgot password\" view. Remember, Fortify is a headless authentication library. If you would like a frontend implementation of Laravel's authentication features that are already completed for you, you should use an [application starter kit](/docs/{{version}}/starter-kits).\n\nAll of Fortify's view rendering logic may be customized using the appropriate methods available via the `Laravel\\Fortify\\Fortify` class. Typically, you should call this method from the `boot` method of your application's `App\\Providers\\FortifyServiceProvider` class:\n\n```php\nuse Laravel\\Fortify\\Fortify;\n\n/**\n * Bootstrap any application services.\n */\npublic function boot(): void\n{\n    Fortify::requestPasswordResetLinkView(function () {\n        return view('auth.forgot-password');\n    });\n\n    // ...\n}\n```\n\nFortify will take care of defining the `/forgot-password` endpoint that returns this view. Your `forgot-password` template should include a form that makes a POST request to the `/forgot-password` endpoint.\n\nThe `/forgot-password` endpoint expects a string `email` field. The name of this field / database column should match the `email` configuration value within your application's `fortify` configuration file.\n\n---\n\n## Passwords Customization\nPasswords | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/passwords.md\n\n\n## Customization\n\n---\n\n## Passwords\nPasswords | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/passwords.md\n\n# Resetting Passwords\n\n- [Introduction](#introduction)\n    - [Configuration](#configuration)\n    - [Driver Prerequisites](#driver-prerequisites)\n    - [Model Preparation](#model-preparation)\n    - [Configuring Trusted Hosts](#configuring-trusted-hosts)\n- [Routing](#routing)\n    - [Requesting the Password Reset Link](#requesting-the-password-reset-link)\n    - [Resetting the Password](#resetting-the-password)\n- [Deleting Expired Tokens](#deleting-expired-tokens)\n- [Customization](#password-customization)\n\n---\n\n## Vite Advanced Customization Dev Server Cross-Origin Resource Sharing (CORS)\nVite | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/vite.md\n\n\n### Dev Server Cross-Origin Resource Sharing (CORS)\n\nIf you are experiencing Cross-Origin Resource Sharing (CORS) issues in the browser while fetching assets from the Vite dev server, you may need to grant your custom origin access to the dev server. Vite combined with the Laravel plugin allows the following origins without any additional configuration:\n\n- `::1`\n- `127.0.0.1`\n- `localhost`\n- `*.test`\n- `*.localhost`\n- `APP_URL` in the project's `.env`\n\nThe easiest way to allow a custom origin for your project is to ensure that your application's `APP_URL` environment variable matches the origin you are visiting in your browser. For example, if you visiting `https://my-app.laravel`, you should update your `.env` to match:\n\n```env\nAPP_URL=https://my-app.laravel\n```\n\nIf you need more fine-grained control over the origins, such as supporting multiple origins, you should utilize [Vite's comprehensive and flexible built-in CORS server configuration](https://vite.dev/config/server-options.html#server-cors). For example, you may specify multiple origins in the `server.cors.origin` configuration option in the project's `vite.config.js` file:\n\n```js\nimport { defineConfig } from 'vite';\nimport laravel from 'laravel-vite-plugin';\n\nexport default defineConfig({\n    plugins: [\n        laravel({\n            input: 'resources/js/app.js',\n            refresh: true,\n        }),\n    ],\n    server: {  // [tl! add]\n        cors: {  // [tl! add]\n            origin: [  // [tl! add]\n                'https://backend.laravel',  // [tl! add]\n                'http://admin.laravel:8566',  // [tl! add]\n            ],  // [tl! add]\n        },  // [tl! add]\n    },  // [tl! add]\n});\n```\n\nYou may also include regex patterns, which can be helpful if you would like to allow all origins for a given top-level domain, such as `*.laravel`:\n\n```js\nimport { defineConfig } from 'vite';\nimport laravel from 'laravel-vite-plugin';\n\nexport default defineConfig({\n    plugins: [\n        laravel({\n            input: 'resources/js/app.js',\n            refresh: true,\n        }),\n    ],\n    server: {  // [tl! add]\n        cors: {  // [tl! add]\n            origin: [ // [tl! add]\n                // Supports: SCHEME://DOMAIN.laravel[:PORT] [tl! add]\n                /^https?:\\/\\/.*\\.laravel(:\\d+)?$/, //[tl! add]\n            ], // [tl! add]\n        }, // [tl! add]\n    }, // [tl! add]\n});\n```\n\n---\n\n## Fortify Installation Disabling Views Disabling Views and Password Reset\nFortify | laravel/fortify@latest | Source: https://github.com/laravel/docs/blob/13.x/fortify.md\n\n\n#### Disabling Views and Password Reset\n\nIf you choose to disable Fortify's views and you will be implementing password reset features for your application, you should still define a route named `password.reset` that is responsible for displaying your application's \"reset password\" view. This is necessary because Laravel's `Illuminate\\Auth\\Notifications\\ResetPassword` notification will generate the password reset URL via the `password.reset` named route.\n\n---\n\n## Vite Advanced Customization\nVite | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/vite.md\n\n\n## Advanced Customization\n\nOut of the box, Laravel's Vite plugin uses sensible conventions that should work for the majority of applications; however, sometimes you may need to customize Vite's behavior. To enable additional customization options, we offer the following methods and options which can be used in place of the `@vite` Blade directive:\n\n```blade\n<!doctype html>\n<head>\n    {{-- ... --}}\n\n    {{\n        Vite::useHotFile(storage_path('vite.hot')) // Customize the \"hot\" file...\n            ->useBuildDirectory('bundle') // Customize the build directory...\n            ->useManifestFilename('assets.json') // Customize the manifest filename...\n            ->withEntryPoints(['resources/js/app.js']) // Specify the entry points...\n            ->createAssetPathsUsing(function (string $path, ?bool $secure) { // Customize the backend path generation for built assets...\n                return \"https://cdn.example.com/{$path}\";\n            })\n    }}\n</head>\n```\n\nWithin the `vite.config.js` file, you should then specify the same configuration:\n\n```js\nimport { defineConfig } from 'vite';\nimport laravel from 'laravel-vite-plugin';\n\nexport default defineConfig({\n    plugins: [\n        laravel({\n            hotFile: 'storage/vite.hot', // Customize the \"hot\" file...\n            buildDirectory: 'bundle', // Customize the build directory...\n            input: ['resources/js/app.js'], // Specify the entry points...\n        }),\n    ],\n    build: {\n      manifest: 'assets.json', // Customize the manifest filename...\n    },\n});\n```\n\n---\n\n## Validation Validating Passwords Defining Default Password Rules\nValidation | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/validation.md\n\n\n#### Defining Default Password Rules\n\nYou may find it convenient to specify the default validation rules for passwords in a single location of your application. You can easily accomplish this using the `Password::defaults` method, which accepts a closure. The closure given to the `defaults` method should return the default configuration of the Password rule. Typically, the `defaults` rule should be called within the `boot` method of one of your application's service providers:\n\n```php\nuse Illuminate\\Validation\\Rules\\Password;\n\n/**\n * Bootstrap any application services.\n */\npublic function boot(): void\n{\n    Password::defaults(function () {\n        $rule = Password::min(8);\n\n        return $this->app->isProduction()\n            ? $rule->mixedCase()->uncompromised()\n            : $rule;\n    });\n}\n```\n\nThen, when you would like to apply the default rules to a particular password undergoing validation, you may invoke the `defaults` method with no arguments:\n\n```php\n'password' => ['required', Password::defaults()],\n```\n\nOccasionally, you may want to attach additional validation rules to your default password validation rules. You may use the `rules` method to accomplish this:\n\n```php\nuse App\\Rules\\ZxcvbnRule;\n\nPassword::defaults(function () {\n    $rule = Password::min(8)->rules([new ZxcvbnRule]);\n\n    // ...\n});\n```\n\n---\n\n## Vite Custom Base URLs\nVite | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/vite.md\n\n\n## Custom Base URLs\n\nIf your Vite compiled assets are deployed to a domain separate from your application, such as via a CDN, you must specify the `ASSET_URL` environment variable within your application's `.env` file:\n\n```env\nASSET_URL=https://cdn.example.com\n```\n\nAfter configuring the asset URL, all re-written URLs to your assets will be prefixed with the configured value:\n\n```text\nhttps://cdn.example.com/build/assets/app.9dce8d17.js\n```\n\nRemember that [absolute URLs are not re-written by Vite](#url-processing), so they will not be prefixed.\n\n---\n\n## Validation Validating Passwords\nValidation | laravel/framework@12.x | Source: https://github.com/laravel/docs/blob/12.x/validation.md\n\n\n## Validating Passwords\n\nTo ensure that passwords have an adequate level of complexity, you may use Laravel's `Password` rule object:\n\n```php\nuse Illuminate\\Support\\Facades\\Validator;\nuse Illuminate\\Validation\\Rules\\Password;\n\n$validator = Validator::make($request->all(), [\n    'password' => ['required', 'confirmed', Password::min(8)],\n]);\n```\n\nThe `Password` rule object allows you to easily customize the password complexity requirements for your application, such as specifying that passwords require at least one letter, number, symbol, or characters with mixed casing:\n\n```php\n// Require at least 8 characters...\nPassword::min(8)\n\n// Require at least one letter...\nPassword::min(8)->letters()\n\n// Require at least one uppercase and one lowercase letter...\nPassword::min(8)->mixedCase()\n\n// Require at least one number...\nPassword::min(8)->numbers()\n\n// Require at least one symbol...\nPassword::min(8)->symbols()\n```\n\nIn addition, you may ensure that a password has not been compromised in a public password data breach leak using the `uncompromised` method:\n\n```php\nPassword::min(8)->uncompromised()\n```\n\nInternally, the `Password` rule object uses the [k-Anonymity](https://en.wikipedia.org/wiki/K-anonymity) model to determine if a password has been leaked via the [haveibeenpwned.com](https://haveibeenpwned.com) service without sacrificing the user's privacy or security.\n\nBy default, if a password appears at least once in a data leak, it will be considered compromised. You can customize this threshold using the first argument of the `uncompromised` method:\n\n```php\n// Ensure the password appears less than 3 times in the same data leak...\nPassword::min(8)->uncompromised(3);\n```\n\nOf course, you may chain all the methods in the examples above:\n\n```php\nPassword::min(8)\n    ->letters()\n    ->mixedCase()\n    ->numbers()\n    ->symbols()\n    ->uncompromised()\n```\n\n_[Truncated]_"}]


rg -n "^### customers|^### customer_addresses|^### orders" specs/01-DATABASE-SCHEMA.md


sed -n '730,880p' specs/01-DATABASE-SCHEMA.md


sed -n '320,470p' specs/06-AUTH-AND-SECURITY.md


find app/Policies -maxdepth 1 -type f -print | sort | xargs -n1 basename


/bin/zsh
-lc
sed -n '1,220p' config/fortify.php

<?php

use Laravel\Fortify\Features;

return [

    /*
    |--------------------------------------------------------------------------
    | Fortify Guard
    |--------------------------------------------------------------------------
    |
    | Here you may specify which authentication guard Fortify will use while
    | authenticating users. This value should correspond with one of your
    | guards that is already present in your "auth" configuration file.
    |
    */

    'guard' => 'web',

    /*
    |--------------------------------------------------------------------------
    | Fortify Password Broker
    |--------------------------------------------------------------------------
    |
    | Here you may specify which password broker Fortify can use when a user
    | is resetting their password. This configured value should match one
    | of your password brokers setup in your "auth" configuration file.
    |
    */

    'passwords' => 'users',

    /*
    |--------------------------------------------------------------------------
    | Username / Email
    |--------------------------------------------------------------------------
    |
    | This value defines which model attribute should be considered as your
    | application's "username" field. Typically, this might be the email
    | address of the users but you are free to change this value here.
    |
    | Out of the box, Fortify expects forgot password and reset password
    | requests to have a field named 'email'. If the application uses
    | another name for the field you may define it below as needed.
    |
    */

    'username' => 'email',

    'email' => 'email',

    /*
    |--------------------------------------------------------------------------
    | Lowercase Usernames
    |--------------------------------------------------------------------------
    |
    | This value defines whether usernames should be lowercased before saving
    | them in the database, as some database system string fields are case
    | sensitive. You may disable this for your application if necessary.
    |
    */

    'lowercase_usernames' => true,

    /*
    |--------------------------------------------------------------------------
    | Home Path
    |--------------------------------------------------------------------------
    |
    | Here you may configure the path where users will get redirected during
    | authentication or password reset when the operations are successful
    | and the user is authenticated. You are free to change this value.
    |
    */

    'home' => '/dashboard',

    /*
    |--------------------------------------------------------------------------
    | Fortify Routes Prefix / Subdomain
    |--------------------------------------------------------------------------
    |
    | Here you may specify which prefix Fortify will assign to all the routes
    | that it registers with the application. If necessary, you may change
    | subdomain under which all of the Fortify routes will be available.
    |
    */

    'prefix' => '',

    'domain' => null,

    /*
    |--------------------------------------------------------------------------
    | Fortify Routes Middleware
    |--------------------------------------------------------------------------
    |
    | Here you may specify which middleware Fortify will assign to the routes
    | that it registers with the application. If necessary, you may change
    | these middleware but typically this provided default is preferred.
    |
    */

    'middleware' => ['web'],

    /*
    |--------------------------------------------------------------------------
    | Rate Limiting
    |--------------------------------------------------------------------------
    |
    | By default, Fortify will throttle logins to five requests per minute for
    | every email and IP address combination. However, if you would like to
    | specify a custom rate limiter to call then you may specify it here.
    |
    */

    'limiters' => [
        'login' => 'login',
        'two-factor' => 'two-factor',
    ],

    /*
    |--------------------------------------------------------------------------
    | Register View Routes
    |--------------------------------------------------------------------------
    |
    | Here you may specify if the routes returning views should be disabled as
    | you may not need them when building your own application. This may be
    | especially true if you're writing a custom single-page application.
    |
    */

    'views' => true,

    /*
    |--------------------------------------------------------------------------
    | Features
    |--------------------------------------------------------------------------
    |
    | Some of the Fortify features are optional. You may disable the features
    | by removing them from this array. You're free to only remove some of
    | these features, or you can even remove all of these if you need to.
    |
    */

    'features' => [
        Features::registration(),
        Features::resetPasswords(),
        Features::emailVerification(),
        Features::twoFactorAuthentication([
            'confirm' => true,
            'confirmPassword' => true,
            // 'window' => 0
        ]),
    ],

];


sed -n '320,470p' specs/06-AUTH-AND-SECURITY.md

---

### 2.2 Permission Matrix

The `store_users` pivot table links a `User` to a `Store` with a `role`. A user can have different roles in different stores.

| Resource | Action | Owner | Admin | Staff | Support |
|----------|--------|:-----:|:-----:|:-----:|:-------:|
| Store Settings | View | Y | Y | N | N |
| Store Settings | Update | Y | Y | N | N |
| Store | Delete | Y | N | N | N |
| Products | List / View | Y | Y | Y | Y |
| Products | Create | Y | Y | Y | N |
| Products | Update | Y | Y | Y | N |
| Products | Delete / Archive | Y | Y | N | N |
| Products | Restore | Y | Y | N | N |
| Collections | List / View | Y | Y | Y | Y |
| Collections | Create | Y | Y | Y | N |
| Collections | Update | Y | Y | Y | N |
| Collections | Delete | Y | Y | N | N |
| Orders | List / View | Y | Y | Y | Y |
| Orders | Update | Y | Y | Y | N |
| Orders | Cancel | Y | Y | N | N |
| Fulfillments | Create | Y | Y | Y | N |
| Fulfillments | Update / Cancel | Y | Y | Y | N |
| Refunds | Create | Y | Y | N | N |
| Customers | List / View | Y | Y | Y | Y |
| Customers | Update | Y | Y | Y | N |
| Discounts | List / View | Y | Y | Y | Y |
| Discounts | Create | Y | Y | Y | N |
| Discounts | Update | Y | Y | Y | N |
| Discounts | Delete | Y | Y | N | N |
| Themes | List / View | Y | Y | N | N |
| Themes | Create / Upload | Y | Y | N | N |
| Themes | Customize | Y | Y | N | N |
| Themes | Publish | Y | Y | N | N |
| Themes | Delete | Y | Y | N | N |
| Pages | List / View | Y | Y | Y | N |
| Pages | Create | Y | Y | Y | N |
| Pages | Update | Y | Y | Y | N |
| Pages | Delete | Y | Y | N | N |
| Navigation | List / View | Y | Y | Y | N |
| Navigation | Manage | Y | Y | N | N |
| Apps | List / View | Y | Y | N | N |
| Apps | Install / Remove | Y | Y | N | N |
| Analytics | View | Y | Y | Y | N |
| Developers / API | Manage | Y | Y | N | N |
| Staff | List / View | Y | Y | N | N |
| Staff | Invite | Y | Y | N | N |
| Staff | Update Role | Y | Y | N | N |
| Staff | Remove | Y | Y | N | N |
| Shipping Zones | Manage | Y | Y | N | N |
| Tax Settings | Manage | Y | Y | N | N |
| Search Settings | Manage | Y | Y | N | N |

#### Role Group Shorthand

The permission matrix reveals three natural groupings that the authorization layer should use as reusable helpers:

| Group Name | Roles Included | Used For |
|------------|---------------|----------|
| OwnerOnly | Owner | Store deletion, ownership transfer |
| OwnerOrAdmin | Owner, Admin | Settings, themes, staff, developers, navigation, apps, shipping, taxes, search, delete/archive actions |
| OwnerAdminOrStaff | Owner, Admin, Staff | Create/update products, collections, discounts, pages, fulfillments, order updates |
| AnyRole | Owner, Admin, Staff, Support | Read-only listing/viewing of products, orders, customers, collections, discounts |

---

### 2.3 Role Checking Trait

File: `app/Traits/ChecksStoreRole.php`

A reusable trait included in all policies and used by gate definitions. Must provide the following methods:

| Method | Parameters | Returns | Description |
|--------|-----------|---------|-------------|
| `getStoreRole` | User, store_id (int) | StoreUserRole or null | Looks up the user's role for the given store via the `store_users` relationship. Returns null if the user has no role in that store. |
| `hasRole` | User, store_id (int), roles (array of StoreUserRole) | bool | Returns true if the user's role for the store is in the provided list. Returns false if user has no role. |
| `isOwnerOrAdmin` | User, store_id (int) | bool | Shorthand: checks if role is Owner or Admin. |
| `isOwnerAdminOrStaff` | User, store_id (int) | bool | Shorthand: checks if role is Owner, Admin, or Staff. |
| `isAnyRole` | User, store_id (int) | bool | Returns true if the user has any role at all in the store. |

**Store ID resolution:** When the policy method receives a model instance (e.g., Product), the store_id comes from the model's `store_id` attribute. When the policy method does not receive a model (e.g., `viewAny`, `create`), the store_id is resolved from the container-bound `current_store`.

---

### 2.4 Laravel Policies

All policies use the `ChecksStoreRole` trait. Laravel 12 auto-discovers policies by convention (`App\Policies\{Model}Policy`), so no manual registration is needed.

Every policy method follows this pattern:
1. Determine the `store_id` (from the model if available, otherwise from the resolved current store).
2. Use the appropriate role-checking helper method.
3. Return a boolean.

#### ProductPolicy

File: `app/Policies/ProductPolicy.php`

| Method | Receives Model? | Required Roles | Store ID Source |
|--------|:--------------:|----------------|-----------------|
| `viewAny(User)` | No | AnyRole | current_store |
| `view(User, Product)` | Yes | AnyRole | product.store_id |
| `create(User)` | No | OwnerAdminOrStaff | current_store |
| `update(User, Product)` | Yes | OwnerAdminOrStaff | product.store_id |
| `delete(User, Product)` | Yes | OwnerOrAdmin | product.store_id |
| `archive(User, Product)` | Yes | OwnerOrAdmin | product.store_id |
| `restore(User, Product)` | Yes | OwnerOrAdmin | product.store_id |

#### OrderPolicy

File: `app/Policies/OrderPolicy.php`

| Method | Receives Model? | Required Roles | Store ID Source |
|--------|:--------------:|----------------|-----------------|
| `viewAny(User)` | No | AnyRole | current_store |
| `view(User, Order)` | Yes | AnyRole | order.store_id |
| `update(User, Order)` | Yes | OwnerAdminOrStaff | order.store_id |
| `cancel(User, Order)` | Yes | OwnerOrAdmin | order.store_id |
| `createFulfillment(User, Order)` | Yes | OwnerAdminOrStaff | order.store_id |
| `createRefund(User, Order)` | Yes | OwnerOrAdmin | order.store_id |

#### CollectionPolicy

File: `app/Policies/CollectionPolicy.php`

| Method | Receives Model? | Required Roles | Store ID Source |
|--------|:--------------:|----------------|-----------------|
| `viewAny(User)` | No | AnyRole | current_store |
| `view(User, Collection)` | Yes | AnyRole | collection.store_id |
| `create(User)` | No | OwnerAdminOrStaff | current_store |
| `update(User, Collection)` | Yes | OwnerAdminOrStaff | collection.store_id |
| `delete(User, Collection)` | Yes | OwnerOrAdmin | collection.store_id |

#### DiscountPolicy

File: `app/Policies/DiscountPolicy.php`

| Method | Receives Model? | Required Roles | Store ID Source |
|--------|:--------------:|----------------|-----------------|
| `viewAny(User)` | No | AnyRole | current_store |
| `view(User, Discount)` | Yes | AnyRole | discount.store_id |
| `create(User)` | No | OwnerAdminOrStaff | current_store |
| `update(User, Discount)` | Yes | OwnerAdminOrStaff | discount.store_id |
| `delete(User, Discount)` | Yes | OwnerOrAdmin | discount.store_id |

#### CustomerPolicy

File: `app/Policies/CustomerPolicy.php`

| Method | Receives Model? | Required Roles | Store ID Source |