These two words are often said in one breath, but they answer different questions:
- Authentication: who is making this request?
- Authorization: may that identity perform this action on this resource?
Knowing that a request came from Priya does not mean Priya may delete any project. Keeping that distinction sharp prevents both security bugs and muddled code.
Authentication is the evidence of identity
At login, the server verifies evidence: usually an email and password, perhaps an OAuth provider, a passkey, or a service API key. After that moment, the browser or client needs a credential it can present on later requests. The server should never receive a password again just to load a profile.
Passwords deserve a few non-negotiables:
- store a slow, salted password hash, never the password itself;
- use a well-maintained authentication library or provider where possible;
- rate limit attempts and log suspicious activity;
- use TLS so credentials are not exposed in transit;
- provide a safe account recovery path.
Rolling your own crypto or token format is almost never a learning project worth shipping.
Sessions: a server-side memory of login
With a session, the server creates an opaque random session id after login and stores the associated user id server-side. The browser usually holds the id in a cookie.
The cookie should usually be HttpOnly (JavaScript cannot read it), Secure (HTTPS only), and set with an intentional SameSite policy. Cookie-based authentication also requires CSRF thinking: browsers attach cookies automatically, so state-changing requests need an origin check, CSRF token, or another suitable defence.
Sessions make revocation simple: delete the server-side record. They do introduce a lookup, which is generally a very reasonable cost. Put the session store in shared storage when multiple API instances serve traffic.
Tokens: credentials the client presents explicitly
A JSON Web Token (JWT) is a signed string containing claims. The server can verify its signature without looking up a session on every request. A token is not encrypted merely because it is encoded; do not place secrets in its payload.
Short-lived access tokens are often paired with longer-lived refresh tokens:
- login creates a short access token and a refresh credential;
- the client uses the access token on normal API calls;
- when it expires, it exchanges the refresh token for a new access token;
- logout or suspected theft revokes the refresh credential.
This pattern limits the damage from a leaked access token, but it is not “stateless magic.” Refresh token rotation, storage, revocation, device tracking, and incident response all need design. In many browser applications, an ordinary server-side session is simpler and safer.
API keys identify applications, not people
API keys work well for server-to-server integrations. They should be high-entropy secrets, shown only once, scoped to the minimum privileges, and stored hashed or encrypted at rest. Give users a way to name, rotate, and revoke them.
Do not put an API key in a browser bundle or a mobile app and call it a secret. Anyone who runs the app can extract it.
Authorization needs the resource
Role-based checks answer broad questions:
is the actor an organisation admin?Resource-level checks answer the one that matters more often:
is the actor a member of *this* project, and do they have edit permission?Perform authorization close to the use case, where the service has both the actor and the resource. Middleware can establish identity; it usually cannot make the whole permission decision before it knows which project a route will load.
For sensitive resources, returning 404 rather than 403 can avoid confirming that the resource exists. Choose this deliberately and use it consistently.
Keep identity information small and current
An authenticated context might include actorId, organisation id, and high-level roles. Do not blindly trust a years-old token claim for fast-changing permissions such as “can approve payments.” For high-risk actions, look up current permissions or maintain a carefully designed revocation/version mechanism.
Always record audit events for consequential actions: who did what, to which resource, and when. A request id makes those records and logs much easier to follow.
A healthy request flow
For DELETE /projects/42, a robust path is:
- request middleware supplies a correlation id;
- authentication verifies the credential and identifies the actor;
- the service loads project 42;
- the service checks the actor’s permission on that project;
- the service applies business rules (for example, billing records prevent deletion);
- the operation is performed and audited;
- the API returns an appropriate response.
Authentication gets you a name. Authorization decides what that name can do. Treating them as separate steps is the foundation; the exact session or token mechanism comes after that.
Browser, mobile app, and service are different callers
There is no single “best auth” answer without knowing the client. A same-site web application often benefits from a secure, HttpOnly session cookie because the browser sends it without application JavaScript handling the secret. A native mobile app may use short-lived access tokens with a platform-provided secure store and a refresh flow. A server integration generally needs a scoped API key, OAuth client credential, or signed service identity.
The shared discipline is the same: issue the minimum privilege, keep credentials short-lived or revocable where practical, and make rotation routine rather than an emergency-only procedure. Start with the simplest mechanism that your client and threat model support. Security designs become fragile when they add token machinery before anyone can explain which risk it reduces.