PHPackages                             everware/laravel-fortify-sanctum - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. everware/laravel-fortify-sanctum

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

everware/laravel-fortify-sanctum
================================

Automatically integrate Laravel Fortify with Laravel Sanctum so Fortify gives out Sanctum tokens on login while maintaining default Fortify functionality like two factor authentication. Also allows the use of 'api' middleware and makes login/sessions work without cookies (makes Fortify "stateless"-ish by creating temporary sessions).

1.0.5(3mo ago)0181MITPHP

Since Sep 25Pushed 3mo agoCompare

[ Source](https://github.com/EverwareSW/laravel-fortify-sanctum)[ Packagist](https://packagist.org/packages/everware/laravel-fortify-sanctum)[ RSS](/packages/everware-laravel-fortify-sanctum/feed)WikiDiscussions v1 Synced 1mo ago

READMEChangelogDependencies (6)Versions (8)Used By (0)

[![Packagist Version](https://camo.githubusercontent.com/414fc9adb3b11d8e3b6417ff0471034b892a92a208fbd1f59e8a8bc45a2d3e19/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f65766572776172652f6c61726176656c2d666f72746966792d73616e6374756d)](https://packagist.org/packages/everware/laravel-fortify-sanctum)

Laravel Fortify Sanctum integration
===================================

[](#laravel-fortify-sanctum-integration)

This package solves a few things.

1. Mainly, it allows you to make Laravel Fortify give out Sanctum access tokens on login instead of session cookies, without the need to add or overwrite routes and while keeping all Fortify functionality intact (like 2FA, password confirmation and registration).
2. It optionally allows you to use different route middleware (groups) than 'web', so you can use the 'api' middleware group for example.
3. It does so by removing the required use of cookies within Fortify, making the Fortify routes/authentication "stateless" (-ish)\*. This is valuable when working with environments that disallow the use of cookies or sessions.

\* The use of sessions is not completely removed because it is required for the two factor authentication and password confirmation actions within Fortify.

Setup
=====

[](#setup)

First follow the [Laravel Fortify install guide](https://laravel.com/docs/12.x/fortify#installation)
and follow the [Laravel Sanctum install guide](https://laravel.com/docs/12.x/sanctum#installation).
Then install the package:

```
composer require everware/laravel-fortify-sanctum
```

Set `config/fortify.php 'guard'` to:

```
'guard' => 'fortify-sanctum', // originally: 'web',
```

Finally, set `config/fortify.php 'middleware'` to either:

```
// If the middleware (group) does not contain StartSession, add StartTemporarySessionMiddleware and AddAuthTokenMiddleware.
['api', StartTemporarySessionMiddleware::class, AddAuthTokenMiddleware::class],
// Or, if the middleware (group) contains StartSession (like 'web'), only add our AddAuthTokenMiddleware.
['web', AddAuthTokenMiddleware::class],

// Add the imports at the top of the file:
use Everware\LaravelFortifySanctum\Http\Middleware\StartTemporarySessionMiddleware;
use Everware\LaravelFortifySanctum\Http\Middleware\AddAuthTokenMiddleware;
```

**That's it!**

Custom user provider
--------------------

[](#custom-user-provider)

If you use a custom user provider, overwrite our auth guard by adding this to `config/auth.php 'guards'`:

```
'fortify-sanctum' => [
    'driver' => 'fortify-sanctum',
    'provider' => 'users', // Your custom provider here.
],
```

Usage
=====

[](#usage)

Added 'device\_name' field
--------------------------

[](#added-device_name-field)

First, Fortifys `/login` and `/two-factor-challenge` routes now also require a 'device\_name' field, so make sure you add this to your post requests.
We suggest something like: `{ email, password, device_name: window.navigator.userAgent }` in the browser or `{ email, password, device_name: `${Device.deviceName} (${Device.modelName})` }` using Expo Device (React Native).

Token response, two factor &amp; temp session
---------------------------------------------

[](#token-response-two-factor--temp-session)

When you make a successful request to the Fortify login route, you will receive Fortifys original response.
If the users 2fa is disabled, thus successfully logging in, the newly generated Sanctum access token is added to an 'Auth-Token' HTTP response header. And if it's a JSON response, you will also receive the token in the response body; e.g. `{two_factor: false, auth_token: 'thetoken'}`.
When making use of **StartTemporarySessionMiddleware**; if the users 2fa is enabled, you will receive a 'Temporary-Session-ID' HTTP header (instead of Set-Cookie) along with the response data `{two_factor: true}` (when expecting a JSON response).
You can then make a post request containing the users OTP 'code' and the new 'device\_name' field (see above) to `/two-factor-challenge` with this session id value in a 'Temporary-Session-ID' HTTP header.
Note that the session id is regenerated on every request, so if for example the request to `/two-factor-challenge` fails in any way (e.g. 422 validation), that response will contain a new 'Temporary-Session-ID' HTTP header which you will need use in the next request (the old id is now obsolete).

Password confirmation
---------------------

[](#password-confirmation)

When not making use of StartTemporarySessionMiddleware; the password confirmation functionality works as it does normally.
When making use of **StartTemporarySessionMiddleware**; the same 'Temporary-Session-ID' HTTP header functionality as described above is used with requests to `/user/confirm-password` and the response header value should be passed to whatever consecutive password-confirm-required route.
Again, note the regeneration mentioned above.

Add data to token response
--------------------------

[](#add-data-to-token-response)

If you want to add data to the authenticated access token response, you can do so by setting `AddAuthTokenMiddleware::$addDataToResponse` in a service providers register or boot method, or in `bootstrap/app.php`s `withMiddleware()` method. E.g. adding user data:

```
AddAuthTokenMiddleware::$addDataToResponse = fn(array $data): array => $data + [
    'user' => \Auth::guard('fortify-sanctum')->user()?->only('id', 'name'),
];
```

Bam! You're done, no custom routes required.
--------------------------------------------

[](#bam-youre-done-no-custom-routes-required)

Testing
=======

[](#testing)

If you want your Feature tests to use Sanctum access tokens as auth (if that's what you use for your APIs auth, you should strive to have your tests be as similar to production as possible), you can add `use SetUpFortifySanctumTests` to your TestCase class or your feature test class(es) (for pest feature test files add `uses(SetUpFortifySanctumTests::class);`)
and add the import `use Everware\LaravelFortifySanctum\Tests\Concerns\SetUpFortifySanctumTests;` at the top of the file.
Now, when you call `$this->actingAs($user)` in your tests, it will create and use Sanctum access tokens instead of session cookies\*.
\* Laravel doesn't originally use actual cookies when running `actingAs()` but rather sets that user on a singleton Auth guard.

Troubleshooting
===============

[](#troubleshooting)

Make sure no Laravel Breeze or Starter Kit auth routes conflict with the Fortify routes.
Make sure your User model implements trait `use HasApiTokens` (and `use TwoFactorAuthenticatable` if you want 2FA) as per [Sanctum's requirements](https://laravel.com/docs/12.x/sanctum#issuing-api-tokens).

Flowchart
=========

[](#flowchart)

How Laravel Fortify works in combination with Laravel Sanctum is quite complex, so I've created a model which visualizes the main parts of the combined architecture:

 ```
---
config:
  layout: elk
---
flowchart TD
    A["SessionManager"] -- creates --> n15["SessionHandlers-NullSessionHandler-ArraySessionHandler-CookieSessionHandler-FileSessionHandler: (native)-**DatabaseSessionHandler**: (default)-CacheBasedSessionHandler: (apc/memcached/redis/dynamodb)"]
    A -- also creates --> B("Store or EncryptedStore")
    A -- is dependency injected into (SessionServiceProvider::register()) --> n2@{ label: "StartSession ('web' middleware)" }
    n2 -- "Tells manager to create Store containing Handler and calls Store::setId() using cookie value.Then calls Store::startSession() (which loads session data) and after $next() adds cookie to response and saves session." --> B
    n2 -- sets on Request (so not when 'api' middleware) --> n3["SymfonySessionDecorator"]
    n3 -- wraps --> B
    n4["AuthenticatedSessionController(/login)"] -- invalidates (destroy/logout) --> n3
    n5@{ label: "AuthenticateSession (Sanctum middleware, only used when middleware 'web' or 'statefulApi()' in EnsureFrontendRequestsAreStateful)" } -- might call flush --> B
    n6["PrepareAuthenticatedSession (Fortify Action)"] -- calls regenerate --> B
    n4 -- creates and runs on login --> n6 & n22["AttemptToAuthenticate(Fortify Action)"]
    n7["TwoFactorAuthenticatedSessionController(/two-factor-challenge, store)"] -- calls regenerate on store (two factor login) --> B
    n8["TwoFactorAuthenticationController(/user/two-factor-authentication, store)"] -- creates and runs (store) --> n9["EnableTwoFactorAuthentication (Fortify Action)"]
    n9 -- dispatches --> n10["TwoFactorAuthenticationEnabled (Fortify Event, not used within Fortify or Sanctum)"]
    n7 -- uses --> n11["TwoFactorLoginRequest(checks/validates posted 2fa code/otp)"]
    n8 -.- n7
    n8 -.-> n12["ConfirmedTwoFactorAuthenticationController(/user/confirmed-two-factor-authentication, store)"] & n16["TwoFactorQrCodeController(/user/two-factor-qr-cod)"]
    n12 -- creates and runs (store) --> n13["ConfirmTwoFactorAuthentication(Fortify Action)"]
    n13 --> n14["TwoFactorAuthenticationConfirmed(Fortify Event, not used within Fortify or Sanctum)"]
    n11 -- "by calling challengedUser(), validRecoveryCode(), hasValidCode(), remember() &amp; session()-&gt;regenerate(), which all need" --> B
    n15 -- is injected into and returns --> B
    n4 -.-> n7
    n16 -.-> n12
    n17["Request"] -- user() into AuthServiceProvider::registerRequestRebindHandler() into --> n18["AuthManager"]
    n18 -- creates (from __construct() into guard()) --> n19["Guard (Illuminate Contract)-SessionGuard: (implements StatefulGuard)-TokenGuard-RequestGuard: (SanctumServiceProvider::configureGuard() &amp; AuthManager::viaRequest() but unused)StatefulGuard used in more than shown below (e.g. register &amp; password reset stuff)."]
    n19 -- SessionGuard uses --> B
    n19 -- created by Sanctum --> n20["RequestGuard"]
    n20 -- has parameter --> n21["Guard (Sanctum, not Illuminate Contract)"]
    n21 -- checks other guards (not sanctum) for auth --> n18
    n21 -- and if not authed by others, uses bearer token to auth and set user in --> n17
    n19 -- StatefulGuard (SessionGuard) is dependency injected into --> n4 & n7 & n22
    n19 -- StatefulGuard (SessionGuard) is dependency injected in --> n11
    n2@{ shape: rect}
    n5@{ shape: rect}
    n11:::Peach
    n17:::Aqua
classDef Peach stroke-width:1px, stroke-dasharray:none, stroke:#FBB35A, fill:#FFEFDB, color:#8F632D
classDef Aqua stroke-width:1px, stroke-dasharray:none, stroke:#46EDC8, fill:#DEFFF8, color:#378E7A
linkStyle 3 stroke:#FF6D00,fill:none
linkStyle 20 stroke:#FF6D00,fill:none
linkStyle 31 stroke:#FF6D00,fill:none
linkStyle 32 stroke:#FF6D00,fill:none
linkStyle 33 stroke:#FF6D00,fill:none
linkStyle 34 stroke:#FF6D00,fill:none
```

      Loading

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance81

Actively maintained with recent releases

Popularity13

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity40

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~22 days

Recently: every ~33 days

Total

7

Last Release

100d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/556a7801f3778e78ca2328f5010017386c73e87affb5b1d0785651ee557d7742?d=identicon)[Ken-vdE](/maintainers/Ken-vdE)

---

Top Contributors

[![Ken-vdE](https://avatars.githubusercontent.com/u/15888558?v=4)](https://github.com/Ken-vdE "Ken-vdE (26 commits)")

---

Tags

apilaravelauthAuthenticationsanctumstatelessfortify

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/everware-laravel-fortify-sanctum/health.svg)

```
[![Health](https://phpackages.com/badges/everware-laravel-fortify-sanctum/health.svg)](https://phpackages.com/packages/everware-laravel-fortify-sanctum)
```

###  Alternatives

[hasinhayder/tyro

Tyro - The ultimate Authentication, Authorization, and Role &amp; Privilege Management solution for Laravel 12 &amp; 13

6712.1k2](/packages/hasinhayder-tyro)[auth0/login

Auth0 Laravel SDK. Straight-forward and tested methods for implementing authentication, and accessing Auth0's Management API endpoints.

2745.0M3](/packages/auth0-login)[benbjurstrom/cognito-jwt-guard

A laravel auth guard for JSON Web Tokens issued by Amazon AWS Cognito

1113.1k](/packages/benbjurstrom-cognito-jwt-guard)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
