Skip to content

Sanctum vs Passport: Most Teams Pick the Expensive One

Passport implements OAuth2, which is the right answer for third-party clients and an expensive mistake for your own frontend. The decision turns on one question about who the consumer is.

4 min read

This is the most common avoidable decision in a Laravel API, and it goes the wrong way often enough to be worth a whole article.

The question is not which package is better. It is who is holding the token.

What OAuth2 is actually for

OAuth2 exists so that a third party can act on a user's behalf without the user handing over their password. That is the problem it solves: delegation across a trust boundary. The consent screen, the authorisation code, the client credentials, the scopes - all of it exists to make that specific exchange safe.

If the client is your own React application or your own mobile app, there is no trust boundary and no delegation. The user is authenticating with you, directly. OAuth2 solves nothing here and charges you for the machinery anyway.

What that costs when it is wrong

Passport brings an OAuth2 server into your application: client tables, authorisation codes, access and refresh tokens, key generation, token introspection, and an upgrade surface that has to be kept current.

Your team now maintains an OAuth2 server. They will debug refresh token rotation, explain client credentials to somebody, and handle key rotation in deployment. All of it to let your own mobile app log in.

It also gets built wrong in a recognisable way: password grant used because the redirect flow makes no sense for a first-party app, the client secret shipped inside that app where it is not a secret, and a token lifetime somebody set to a year so people stop complaining.

Sanctum, which is what most APIs want

Opaque tokens, stored hashed, with abilities and per-token revocation:

$token = $user->createToken('mobile', ['orders:read'])->plainTextToken;

Nothing to stand up, nothing to rotate, and revocation is deleting a row. For a mobile app, a CLI, or a server-to-server key issued to a customer, this is the right shape.

The part people miss is that Sanctum has a second mode that is better still.

For a first-party SPA, use no token at all

If your single-page application is served from the same top-level domain as the API, Sanctum authenticates it with the ordinary session cookie:

GET  /sanctum/csrf-cookie      → sets the CSRF cookie
POST /login                    → normal session login
GET  /api/orders               → cookie-authenticated, CSRF protected

No token in localStorage, so nothing for a cross-site scripting bug to steal. HttpOnly, SameSite, CSRF protection - the whole set of browser protections that token-in-storage authentication gives up.

Teams skip this because "it is an API, so it needs tokens". It does not, and this is the most secure arrangement available to a first-party browser client.

When Passport is genuinely right

Other companies' applications integrate with you. They need to act for your users, you need consent screens and scoped access, and you need to revoke one integration without touching anything else.

You are the identity provider. Other systems authenticate against you.

A standards requirement. A partner or a procurement process specifies OAuth2 and that is not negotiable.

Notice what these have in common: somebody outside your organisation holds the credential. That is the whole test.

Migrating between them

From Passport to Sanctum, where Passport was chosen by mistake: issue Sanctum tokens on login, accept both during a transition window, then stop issuing Passport tokens and remove it. Bounded, and usually a week.

From Sanctum to Passport, when a real third-party integration appears: install Passport for the third-party flows and keep Sanctum for your own clients. They coexist, with different guards. This is another reason starting with Sanctum costs you nothing - you are not painted into a corner, you are simply not paying up front.

The rule, once more

Your client, your token: Sanctum. Somebody else's client acting for your user: Passport.

If you cannot name the third party, you do not need OAuth2 yet - and the versioning policy you write for that API will matter far more to its consumers than which package issued the token.

Bahrain is the one market where this choice is usually made for you. Open banking there is live, not planned, and the other side of the integration expects OAuth 2 with the scopes and consent flow that come with it.

Related questions

What is the one-sentence rule?
If the client belongs to you, use Sanctum; if it belongs to somebody else, use Passport. Everything else in the comparison follows from that, because OAuth2 exists to let a third party act on a user's behalf without holding their password - a problem you do not have with your own application.
Can we start with Sanctum and move later?
Yes, and it is the right order. Adding Passport when a third-party integration actually appears is a bounded piece of work, and the two can run alongside each other during the transition. Starting with Passport in case you need it is paying for a problem you may never have.
Is Sanctum less secure?
No. It issues opaque tokens stored hashed in your database, with abilities and revocation, and for a first-party client that is exactly the right shape. OAuth2 is not more secure in the abstract - it solves delegation, which is a different problem from authentication.
How does the SPA mode work?
It does not use tokens at all. A first-party single-page application on the same top-level domain authenticates with the ordinary session cookie, with CSRF protection intact - so there is no token in browser storage to steal. That is the most secure option available and it is the one people skip.

← Back to all articles

Call us+1 848 272 7583WhatsApp+90 850 308 5436Emailinfo@codefacture.comContact page