This article is published in English.
Mapping the Auth Vocabulary: API Keys, Sessions, JWT, OAuth2, OIDC, SSO
Learn how API keys, sessions, JWTs, OAuth2, OpenID Connect and SSO fit together by sorting each one under a single question: who is calling, or what may they do.
A developer adds "Sign in with Google" to a project, sees an access token come back, and calls the job done. Then a colleague asks a simple question: how does the app actually know which user this is? Very often the honest answer is that it does not, because what was built is delegated authorization, not login. Terms like JWT, session, OAuth2, OIDC and SSO are usually explained one at a time, which is exactly why they blur together. This article places each of them on a single map so you can tell which problem a given piece of your stack is really solving and choose the right tool for the next one.
Two questions behind every auth mechanism
Nearly everything in this space answers one of two questions.
- Authentication asks who are you? It is the process of verifying an identity, whether that identity belongs to a person, a backend service or a device.
- Authorization asks what are you allowed to do? It comes after identity is established and decides which resources and actions are available.
HTTP already encodes the split in its status codes. A 401 Unauthorized response means the caller has not proven who they are (despite the misleading name, it is about authentication). A 403 Forbidden response means the server knows exactly who is calling and still refuses the request. If your API returns 403 for a missing token or 401 for a user who lacks a role, clients cannot tell whether to prompt for login or show a "no access" message.
A physical analogy helps. At an office entrance, a guard checks your employee ID card; that is authentication. Once inside, your badge opens some doors and not others; that is authorization. One step establishes identity, the other applies permissions, and a system can pass the first while failing the second. For a deeper look at where each check belongs inside application code, see authentication vs authorization and where each one belongs.
Keep these two questions in mind for the rest of the map. Each mechanism below is easier to understand once you know which one it answers.
API keys: identifying a client, not a person
API keys are the simplest form of client authentication. The provider issues you a unique string, you send it with each request, and the server compares it against the keys it has on record. Many APIs accept it as a bearer credential in the standard header:
Authorization: Bearer your-api-key-here
Other providers use a custom header such as X-API-Key; the idea is the same. What the key does not do is describe anyone. It is an opaque value, so the server must look it up to learn which account is calling. It has no built-in expiry unless you add one, and whoever holds a leaked key has the same access as its rightful owner. That makes rotation, scoping and secret storage your responsibility.
HTTP Basic authentication, which sends a base64-encoded username and password in a header, still exists as well. Base64 is an encoding, not encryption, so Basic auth is only safe over TLS, and it is hard to justify outside very simple internal tools. API keys are the more common lightweight choice, and they fit well when you control both ends of the connection or when a service is billing and rate-limiting per account.
Typical places you will meet API keys:
- AI model APIs
- Payment gateways
- Weather and other data APIs
- Backend-to-backend calls between your own services
Notice what is missing from that list: end users logging into your app. An API key identifies a calling application or account, not the human in front of the screen.
Sessions: server-side state behind a cookie
Long before JWTs became popular, sessions were the default way to keep users logged in, and they remain a strong option for server-rendered applications.
The flow is straightforward. The user submits credentials, the server verifies them and creates a session record in some store (memory, Redis or a database), and the response sets a cookie containing only the session ID. On every later request the browser sends the cookie back, and the server looks up the ID to find the session and the user attached to it.
This design is stateful, but that is also its strength. The server holds the truth, so logging a user out or revoking a compromised session is as simple as deleting a record. The cookie itself carries nothing sensitive beyond a random identifier.
The cost appears when you scale horizontally. If several servers handle traffic, they all need to reach the same session store, or a user logged in on one instance will look anonymous on the next. A shared Redis instance solves this well in practice, but it is one more component to deploy, monitor and configure correctly, and a misconfigured session store is the kind of problem that surfaces at the worst possible moment during a release.
Sessions remain an excellent fit for:
- Traditional server-rendered web apps
- Admin dashboards
- Applications where instant revocation matters more than statelessness
JWT: self-contained, signed and readable
A JSON Web Token is a signed JSON object carrying claims such as a user ID, roles and an expiry time. It is made of three base64url-encoded segments joined by dots:
Header.Payload.Signature
The header names the signing algorithm, the payload holds the claims, and the signature lets the server confirm that neither part was altered by anyone without the signing key. Because the claims travel inside the token, a server can authenticate a request by verifying the signature and reading the payload, with no database lookup. That property is why JWTs suit stateless and distributed systems.
Signed does not mean secret
The most common misunderstanding is that a JWT hides its contents. It does not. A standard JWT is signed, not encrypted, and anyone holding it can decode the payload with a single base64 call. Never put passwords, personal data you would not show the user, or internal secrets into the claims on the assumption that they are private. When a JWT-related incident happens, this mistaken assumption is frequently at its root. (Encrypted tokens do exist under the JWE specification, but they are a separate format and rarely what a tutorial means by "JWT".)
Access and refresh tokens
Because a JWT stays valid until it expires, the usual pattern pairs two tokens:
- Access token: short-lived, commonly 15 minutes to an hour, and sent with every API request.
- Refresh token: long-lived, from days to weeks, and used only to obtain a new access token without asking the user to log in again.
Store the refresh token in an HttpOnly cookie rather than localStorage, where any injected script could read it. The short access-token lifetime limits the damage of a leak, while the refresh token is where revocation logic can live.
JWTs work well for APIs, mobile clients, single-page apps and distributed services. They did not make sessions obsolete; they trade easy revocation for statelessness, and the right choice depends on your architecture. The comparison of sessions and JWTs as Node.js auth models goes into that trade-off in detail.
OAuth 2.0: delegated access, not login
OAuth 2.0 is the concept most often filed in the wrong drawer. It is an authorization framework, not an authentication protocol. Its job is to let one application access resources held by another service on a user's behalf, without the user ever handing over their password.
In the common authorization code flow, your app redirects the user to the provider's consent screen, which asks something like "Allow this app to view your Google Drive files?". If the user agrees, the provider redirects back with a short-lived authorization code. Your backend exchanges that code for an access token and then calls the provider's API with it.
That access token represents permission to reach certain resources. It is not a statement about who the user is, and the OAuth2 specification does not define its format or require that your app be able to read it. Treating the arrival of an access token as proof that the user is logged in is the classic mistake from the opening scenario, and it has caused real vulnerabilities, for example when a token issued to one app is accepted as proof of identity by another.
OAuth2 is built to answer questions like:
- May this app read the user's Drive files?
- May this app access the user's repositories?
It is not built to answer: who is this user?
OpenID Connect: the identity layer on top of OAuth2
If OAuth2 tells you what an app may access, OpenID Connect adds the missing answer about who the person is. OIDC is a thin identity layer built on top of OAuth2, reusing its redirects and token exchange. When you click "Sign in with Google", the flow running underneath is OIDC, not plain OAuth2.
After the user authenticates, an OIDC provider returns two tokens with different purposes:
- An ID token, which is a JWT describing the user: a stable unique identifier, and typically claims such as name and email.
- An access token, which lets your app call APIs on the user's behalf.
The ID token is what authenticates the user to your application. The access token is what authorizes your app's next actions. Your backend should validate the ID token's signature, issuer, audience and expiry before trusting its claims, and should key user accounts on the stable subject identifier rather than on an email address that can change. Seen this way, OAuth2 alone cannot provide login; OIDC completes it.
SSO: an experience, delivered by protocols
Single Sign-On is often confused with the protocols that implement it. SSO is a user experience pattern: authenticate once and then move between several systems without logging in again. Google is the familiar example; sign in once, and Gmail, Drive, Calendar and YouTube all recognize you.
Two protocols do most of the work behind SSO:
- SAML: XML-based and mature, dominant in enterprise environments such as corporate portals, CRM dashboards and internal tools.
- OpenID Connect: JSON- and JWT-based, more recent, and the usual preference for web and mobile applications.
SAML is notoriously fiddly to implement and debug, so for a new system OIDC is generally the easier path. SAML still earns its place when you must integrate with enterprise identity providers that do not offer OIDC, and plenty of those remain in use.
When someone asks you to "add SSO", the first thing to find out is which protocol their identity provider speaks. That single answer shapes the libraries, configuration and testing work that follow.
Choosing a mechanism
Putting the map together, a rough decision guide looks like this:
- Your service is called by other programs, not people: API keys, scoped and rotated, or OAuth2 client credentials if you need expiring tokens.
- A server-rendered app or admin panel with its own login: sessions with a secure,
HttpOnlycookie. - Stateless APIs, mobile clients or many services verifying the same user: JWT access tokens with refresh tokens.
- Your app needs to act on a user's data in another service: OAuth 2.0.
- You want users to log in with an existing account such as Google: OpenID Connect.
- Employees need one login across many internal or SaaS tools: SSO via OIDC, or SAML where the identity provider requires it.
These options combine. A typical product might use OIDC for login, then issue its own session or JWT, while also holding OAuth2 access tokens for third-party integrations.
Common questions
How do authentication and authorization differ in practice? Authentication verifies identity and fails with HTTP 401; authorization checks permissions and fails with 403. They are separate steps with separate error codes, and merging them leads to real security gaps.
Should you use JWT or sessions? Sessions shine for server-rendered apps that can share a session store. JWTs make more sense for stateless APIs, mobile clients and distributed systems. Decide based on your architecture and revocation needs, not on which option sounds more modern.
Is OAuth2 for authentication or authorization? Authorization. It lets apps access resources on a user's behalf without confirming who that user is. For identity, use OpenID Connect, which extends OAuth2 for exactly that purpose.
Key takeaways
- Sort every mechanism under one question: who is calling? or what may they do?
- API keys identify client applications; they carry no user identity and need your own expiry and rotation.
- Sessions keep state on the server, which makes revocation easy but requires a shared store at scale.
- JWTs are signed, not encrypted; keep secrets out of the payload and refresh tokens out of
localStorage. - OAuth2 grants delegated access; OIDC adds the ID token that actually logs a user in.
- SSO is an experience, implemented with OIDC or SAML depending on the identity provider.
Most confusion in this area, including the "Sign in with Google" mix-up from the opening, comes from blending the two questions. Keep identity and permission apart, and choosing between these tools becomes a matter of fitting each to the question it was designed to answer.