Contents
For a web app whose front end and backend share a domain, sessions in a secure cookie are the most reliable choice: simple, easy to revoke and protected by the browser from script theft. JWTs suit mobile apps and service-to-service calls but need careful revocation and storage. OAuth and OpenID Connect are not alternatives but standards for external sign-in and third-party access.
Here is how the approaches differ, when to choose each and which mistakes are most common.
How does authentication differ from authorisation?
Authentication answers "who is this"; authorisation answers "what may they do". Sessions, JWTs and OAuth mostly solve the first problem and carry that information between requests; checking permissions on specific data and actions is a separate layer needed whatever sign-in method you use.
Authorisation failures — a user reaching someone else's data — top the risk list in the OWASP Top 10. So choosing a sign-in mechanism does not remove the need to check permissions on every request.
How do sessions, JWTs and OAuth work?
A session keeps sign-in state on the server, and the browser sends only its ID in a cookie. A JWT is a signed token that contains the user data itself, so the server can verify it without a storage lookup. OAuth and OpenID Connect describe how to obtain such tokens from an identity provider — Google, a corporate directory or your own authorisation server.
| Criterion | Cookie sessions | JWT | OAuth / OpenID Connect |
|---|---|---|---|
| Where state lives | On the server | Inside the token | With the identity provider |
| Revoking access | Instant: delete the session | Harder: the token lives until expiry | Via the provider and short-lived tokens |
| XSS protection | HttpOnly cookies are hidden from scripts | Depends on where the token is stored | Depends on the client implementation |
| Suits | Web on one domain | Mobile apps, service-to-service | External sign-in, third-party access |
| Complexity | Low | Medium | High; prefer ready-made solutions |
Photo: Unsplash
When should you choose sessions?
Choose sessions for a web app whose front end and API sit on one domain or its subdomains. It is the simplest and safest option: a cookie with HttpOnly, Secure and SameSite flags is invisible to scripts, and signing out or blocking a user takes effect instantly.
// config/session.php — secure session cookie settings
'secure' => true, // HTTPS only
'http_only' => true, // hidden from JavaScript
'same_site' => 'lax', // protects against cross-site requests
'lifetime' => 120, // idle minutes before sign-out
A Vue or React SPA on the same domain can also use sessions — many frameworks ship ready packages for this, such as Sanctum in Laravel.
When do you need JWTs and OAuth?
You need JWTs when the client cannot reliably use cookies or a request passes through several services: mobile apps, partner APIs, microservice communication. You need OAuth and OpenID Connect when users sign in with an external account or a third-party app accesses data on a user's behalf.
Rules for working with JWTs
- Short-lived access tokens — minutes, not days.
- Refresh tokens stored securely and revocable on the server.
- On mobile, tokens go in the system's secure storage; in the browser, never in localStorage.
- Always verify the signature, with the algorithm fixed on the server rather than read from the token.
- No secrets in the token — anyone can read its contents.
Building your own OAuth server is almost never worth it: there are ready identity providers and proven libraries for that.
Which mistakes are most common?
The most common mistakes involve token storage, token lifetime and permission checks: the token sits in localStorage and is stolen via XSS, lives for a month with no revocation, and the server checks that the user is signed in but not that the object belongs to them.
Typical mistakes:
- JWTs with no revocation — a departed employee keeps access until the token expires;
- passwords without slow hashing or without login attempt limits;
- no two-factor authentication for administrators;
- different sign-in mechanisms for web and API without unified permission checks;
- sign-in error messages that reveal whether a user exists.
We covered designing APIs so permissions are checked consistently in how to design a REST API.
In short
- Authentication is who the user is, authorisation is what they may do; check permissions on every request.
- For web on one domain, sessions in an HttpOnly cookie are the best choice.
- JWTs suit mobile apps and service-to-service calls, with short lifetimes and revocation.
- OAuth and OpenID Connect are for external sign-in; use ready-made solutions.
- Never store tokens in localStorage, and enable two-factor authentication for administrators.
FAQ
Can a JWT be stored in localStorage?
Better not: any XSS vulnerability lets an attacker's script read the token. In the browser an HttpOnly cookie is safer; in a mobile app, the system's secure storage.
Is two-factor authentication necessary?
Mandatory for administrators and staff with access to customer data. Offer it to regular users, and in financial products it is often required.
What are passkeys?
Passwordless sign-in based on cryptographic keys stored on the user's device and unlocked with biometrics or a PIN. Passkeys resist phishing and are gradually becoming the standard way to sign in.



