# API key, Basic Auth, session, JWT or OIDC: how to read authentication on a client's system

> The first 401 at a client site is not the worst outcome. Worse is an integration that keeps running while you misunderstand how the system authenticates.

Original: https://fdetimes.net/en/guides/api-key-basic-auth-session-jwt-oidc/

In your first week at a client site, you are asked to connect an agent to their internal system. An engineer on the client side messages you: "Just call the API, auth is already in place." The first request returns 401, and only then do you realise that "already in place" could mean five entirely different mechanisms.

API keys, Basic Auth, session cookies, JWT and OIDC answer different questions, so they also fail in different ways. Misread the mechanism and you can easily build an integration that works on your laptop but breaks in production. Worse, credentials can end up in logs without anyone noticing.

This skill does not require memorising specs. It is the ability to look at a request and answer three questions: where the credential lives, whether the server has to remember anything, and who vouches for the user's identity.

## Basic Auth looks like a hidden password. It is not

Basic Auth is a scheme built into HTTP. The client joins the username and password into the string `username:password`, encodes it in base64, and sends it in a header in the format Twilio's documentation describes: the words `Authorization: Basic`, followed by that base64 string.

The quickest way to see the problem is to try it yourself with a dummy account:

```bash
echo -n 'user:pass' | base64
# dXNlcjpwYXNz

echo 'dXNlcjpwYXNz' | base64 -d
# user:pass
```

No key is needed and there is nothing to crack, because base64 is encoding, not encryption. Postman states plainly that Basic Auth credentials are neither hashed nor encrypted. Swagger's documentation recommends using Basic Auth only alongside other security mechanisms, such as HTTPS.

API keys carry the same class of risk as Basic Auth. Postman defines an API key as an identifier issued to a registered user, and stresses that it must travel over HTTPS to stay safe.

At a client site, the first job is therefore simple: check that every endpoint accepting an API key or Basic Auth runs over HTTPS, including the "internal only" ones.

## Session or token: the difference is who has to remember

The next two mechanisms differ in architecture, not just format. Authgear describes session authentication as stateful: the server holds state in memory and the browser holds a cookie. JWT is stateless; the backend does not need to store the token.

Okta explains token-based auth along the same lines: verify identity once, issue a token, and from then on the server keeps no session record. Authgear also notes that server-stored sessions are harder to scale.

Picture a client with an internal web app that uses session cookies, and you need an agent running on a different domain to call that app's backend. Cookies usually work only within one domain or its subdomains, so your agent will struggle to "borrow" a user's session.

The practical consequence: do not try to emulate a browser to obtain a cookie. Ask the client whether the backend supports tokens for clients that do not run in a browser. If it does not, that is an item to put in scope from the start, not something to leave for a workaround later.

## Open a JWT to see that it keeps no secrets

A JWT has three parts separated by dots: header, payload and signature. You can pull out the middle part and decode it exactly as you did with Basic Auth:

```bash

TOKEN='xxxxx.yyyyy.zzzzz'

echo "$TOKEN" | cut -d. -f2 | base64 -d

# you may need to append '=' characters at the end for correct padding

```

(The comment notes that you may need to add `=` characters at the end for padding.)

According to jwt.io, the signature is used to verify that the message was not changed in transit. It proves data integrity; it does not hide the data. Anyone holding the token can read the payload. So do not put secrets in a JWT that is only signed and not encrypted.

The reverse is just as easy to overlook: the recipient must check the token. Auth0's documentation requires that a received JWT have its signature verified before it is used. If your code simply decodes the payload and reads `user_id` without verifying, anyone can write their own token and impersonate someone else.

**Key point:** Base64 is encoding and protects nothing. A signature proves the data has not been altered, but it keeps nothing secret.

## JWT does not tell you who the user is. OIDC does

Many engineers see that a client uses JWT and assume identity is solved. In fact JWT is only a token format. The OpenID Connect Core spec describes OIDC as a simple identity layer on top of OAuth 2.0, and it is this layer that answers the question "who is this user?"

This distinction shapes how you ask questions in discovery. Do not ask "Do you use JWT?" Ask "Which system issues user identity, and on whose behalf will our agent sign in?"

| Mechanism | Where the credential lives | Does the server keep state? | First risk to check |
|---|---|---|---|
| Basic Auth | `Authorization: Basic` header | No | Endpoint not running HTTPS |
| API key | Defined by the API | No | Key exposed without HTTPS |
| Session | Cookie | Yes | Cross-domain calls, hard to scale |
| JWT | Token held by the client | No | Signature not verified, secrets in the payload |
| OIDC | Identity layer on OAuth 2.0 | Depends on implementation | Confusing a token format with identity |

## A five-minute routine before the first line of code

Start by capturing a real request from the client's application, via DevTools or a proxy, and look at the Authorization header and cookies. This tells you where the credential lives. Next, try decoding it: if it is Basic you will see the username at once; if it is a JWT you will see the payload.

Then ask the client two questions: does the server keep sessions, and who reissues credentials when they expire? Finally, write everything into a short "auth map" and have the client team confirm it. That document becomes your anchor for later troubleshooting.

## Common FDE mistakes

The most common mistake is treating base64 encoding as encryption, then logging the full Authorization header to a debug file. The second is decoding a JWT to get user information while skipping signature verification. The third is trying to reuse a session cookie for a client on another domain, when cookies are inherently tied to one domain.

The hardest mistake to spot is in communication: writing "uses JWT" in the scope document and assuming everything is clear. Until someone can answer "where does identity come from?", the hardest part of the project is still untouched.

This week's exercise: pick a system you are integrating, write an auth map with the four columns in the table above, and check which of these mistakes your team is making.

If you want to use this exercise in an FDE job application, do not take a client's real auth map outside; redo it on a personal project or a fully anonymised version.

Next time someone says "auth is already in place", you will know what to ask next.

**Try this week:**

- Open DevTools on an internal application you use, find the Authorization header or cookie on a request, and place it in exactly one of the five mechanisms
- Take a JWT from a test environment, base64-decode the payload and note the fields that should not be exposed
- Write a one-page 'auth map' for your current project: which mechanism each system uses, where credentials are stored, and who reissues them when they expire

## Sources

- [Basic Authentication (Swagger)](https://swagger.io/docs/specification/authentication/basic-authentication/)

- [Basic Authentication (Twilio)](https://www.twilio.com/docs/glossary/what-is-basic-authentication)

- [What Is API Authentication? Benefits, Methods & Best Practices | Postman](https://www.postman.com/api-platform/api-authentication/)

- [Session vs Token Authentication: Which Should You Choose?](https://www.authgear.com/post/session-vs-token-authentication)

- [JSON Web Token Introduction - jwt.io](https://jwt.io/introduction)

- [JSON Web Tokens (Auth0 Docs)](https://auth0.com/docs/secure/tokens/json-web-tokens)

- [What Is Token-Based Authentication? (Okta)](https://www.okta.com/uk/identity-101/what-is-token-based-authentication/)

- [Final: OpenID Connect Core 1.0 incorporating errata set 2](https://openid.net/specs/openid-connect-core-1_0.html)
