authentication guide
authentication guide
Authentication Guide
Authentication is one of the foundational concepts in software security, but the surrounding terminology can easily become confusing: Session, Cookie, Basic Auth, API Key, Bearer Token, JWT, OAuth, OpenID Connect, Access Token, Refresh Token, and MFA.
The main source of confusion is that these terms do not all describe the same kind of thing, and they do not even operate at the same layer. For example, JWT is a token format, Bearer describes how a token is presented, and OAuth is an authorization framework.
The best way to understand all of this is to start from the basics.
Authentication vs. Authorization
Before anything else, we need to separate two important concepts.
Authentication answers:
Who are you?
Authorization answers:
Now that I know who you are, what are you allowed to do?
For example, when you log in to a website using a username and password, the system is performing authentication.
When the system checks whether that user is allowed to access the admin panel, delete an order, or view another user's information, that is authorization.
In simple terms:
Authentication
↓
Who are you?
Authorization
↓
What are you allowed to do?
In most systems, authentication happens first, and authorization is then performed based on the authenticated identity.
Username and Password
The most familiar authentication method is username and password.
The user enters credentials such as:
Username: ali
Password: MySecret123
The server verifies whether those credentials are valid.
If they are valid, authentication succeeds and the system knows who the user is.
However, there is one extremely important rule:
Passwords must never be stored in plain text.
This is wrong:
ali | hello123
If the database is leaked, every user's password is immediately exposed.
Instead, the password should be processed using a password hashing algorithm such as Argon2 or bcrypt.
Conceptually:
hello123
↓
Password Hashing
↓
$argon2id$v=19$...
The resulting hash is stored in the database.
When the user logs in later, the server verifies the provided password against the stored hash.
Hashing Is Not Encryption
These two concepts should not be confused.
Encryption is generally reversible:
Data
↓
Encryption
↓
Encrypted Data
↓
Decryption
↓
Data
Password hashing is designed to be one-way:
Password
↓
Hash
The server is not supposed to decode the hash and recover the original password.
Passwords are normally stored using password-specific hashing algorithms together with a salt. These algorithms are intentionally relatively expensive to calculate so that password-guessing attacks become more difficult.
The Problem with Passwords
A large part of the password problem comes from user behavior.
Users often choose passwords such as:
123456
password
qwerty
They may also reuse the same password across several websites.
If credentials from one website are leaked, an attacker may try the same username and password on other services.
This type of attack is called Credential Stuffing.
For this reason, passwords alone are not always enough, especially for sensitive systems. This is why MFA is often added as another layer.
Session and Cookie
Suppose the user has successfully entered their username and password and logged in.
A very bad approach would be to send the username and password again with every request:
GET /profile
username=ali
password=123456
Then again:
GET /orders
username=ali
password=123456
And again:
GET /messages
username=ali
password=123456
To avoid this, one traditional and very common solution is a Session.
After a successful login, the server creates a session.
For example:
Session ID:
abc98df712
The server may store something like:
abc98df712 → user_id = 42
The server now knows which user belongs to that session identifier.
What Is a Cookie?
A cookie is a browser mechanism for storing small pieces of data and automatically sending them with matching requests.
The server may return:
Set-Cookie: sessionId=abc98df712
The browser stores that cookie.
On future requests, the browser can automatically send:
Cookie: sessionId=abc98df712
The server receives the session ID and looks it up in its session store:
abc98df712
↓
user_id = 42
↓
Ali
The server therefore knows that the request belongs to Ali.
The complete flow looks roughly like this:
User
│
│ Username + Password
▼
Server
│
│ Credentials are valid
▼
Create Session
│
│ Session ID = abc123
▼
Browser
│
│ Stores Session ID in Cookie
▼
Future Requests
Session and Cookie Are Not the Same Thing
This distinction is important.
A session usually represents authentication state stored on the server.
For example:
abc123:
{
userId: 42,
role: "admin"
}
A cookie exists in the browser and may simply contain the session identifier:
sessionId=abc123
So, in simple terms:
Session → Server-side state
Cookie → Browser mechanism
Cookies can also be used for many things unrelated to authentication.
Logout in Session-Based Authentication
The server can invalidate the session:
delete session abc123
Now, even if the browser sends:
Cookie: sessionId=abc123
the server will no longer find a valid session.
The user is therefore no longer authenticated.
This is one of the useful properties of server-side sessions: the server has direct control and can invalidate a session immediately.
Sessions in Large Systems
If a system has millions of users, managing a large number of sessions can become more complicated.
For that reason, distributed applications often store session data in shared systems such as Redis, allowing multiple backend servers to access the same session store.
Basic Authentication
Basic Authentication is one of the simplest authentication methods supported by HTTP.
The client first combines the username and password:
ali:123456
It then encodes the value using Base64:
YWxpOjEyMzQ1Ng==
And sends it in the HTTP Authorization header:
Authorization: Basic YWxpOjEyMzQ1Ng==
Base64 Is Not Encryption
This is extremely important.
Base64 is an encoding format, not encryption.
If someone has:
YWxpOjEyMzQ1Ng==
they can easily decode it back into:
ali:123456
Therefore:
Base64 ≠ Encryption
Basic Authentication must be used over HTTPS.
HTTPS protects the credentials while they are being transmitted. Base64 itself provides no confidentiality.
Basic Auth vs. Session Authentication
With session-based authentication, a user usually logs in once:
Login
↓
Session ID
↓
Future Requests
With Basic Authentication, credentials are typically sent on every request:
Request 1 → Username + Password
Request 2 → Username + Password
Request 3 → Username + Password
Because of this, Basic Auth is more commonly used for simple APIs, internal tools, development environments, or limited scenarios, rather than as the first choice for a modern public web application.
API Key
Sometimes the client is not a human user.
An application or service may want to call an API.
Suppose we have a weather API.
Each application may receive an API key:
sk_abc123xyz
The client sends it with a request:
GET /weather
x-api-key: sk_abc123xyz
The server verifies the API key and determines which client or project is making the request.
For example:
sk_abc123xyz
↓
Company ABC
What Are API Keys Used For?
API keys can be used for things such as:
API Access
Rate Limiting
Billing
Usage Tracking
For example:
API Key X
→ 10,000 Requests / Month
API Keys Usually Identify an Application
An important point is that an API key does not necessarily identify a human user.
It may simply identify:
API Key
↓
MyWeatherApp
The server may still have no idea whether the current user is Ali or Reza.
So API keys and user authentication are not necessarily the same thing.
An API Key Is a Secret
If an API key is leaked, an attacker may be able to use the API as that client.
Secret API keys should therefore not be placed in public repositories, frontend JavaScript, or other places where users can see them.
An API key should be protected like any other sensitive credential.
Token-Based Authentication
In a token-based model, the user first authenticates.
For example:
Username + Password
The server verifies the credentials and, if valid, issues a token:
token = abc123xyz
From this point onward, the client no longer needs to send the password with each request.
Instead, it sends the token.
For example:
Authorization: Bearer abc123xyz
What Is a Token?
A token is essentially a credential that a client can use to prove that it has been granted some form of access.
A token may simply be a random string:
2f7c9d885937a...
This is often called an Opaque Token.
Or it may be structured, such as a JWT:
eyJhbGciOi...
So a token is not necessarily a JWT.
A useful sentence to remember is:
A JWT can be used as a token, but not every token is a JWT.
What Is a Bearer Token?
Bearer should not be confused with JWT.
Bearer is not a specific token format.
It mainly describes how a credential is presented.
For example:
Authorization: Bearer <token>
The idea behind a Bearer token is roughly:
Whoever possesses the token can use its authority.
A simple analogy is a movie ticket.
If you possess a valid ticket:
Ticket
↓
Entry
the ticket itself is what grants access.
Bearer tokens behave similarly.
If a Bearer token is stolen, an attacker may be able to use it until the token expires or is revoked.
That is why Bearer tokens must be protected carefully.
Access Token
A token that a client uses to access an API or Resource Server is usually called an Access Token.
For example:
GET /profile
Authorization: Bearer ACCESS_TOKEN
Access tokens usually have a relatively short lifetime.
For example:
15 Minutes
If an access token is stolen, the attacker can only use that same token until it expires.
For example:
12:00 → Token stolen
12:15 → Token expires
A short lifetime is therefore a form of damage limitation.
Refresh Token
If an access token expires quickly, we do not want the user to re-enter a username and password every few minutes.
This is where the Refresh Token comes in.
The client can send the refresh token to the Authorization Server:
Refresh Token
↓
Authorization Server
↓
New Access Token
The user can therefore maintain a longer-lived login session while the access tokens used against APIs remain short-lived.
Can a Refresh Token Be Stolen?
Yes.
A refresh token can also be stolen, and in many cases a stolen refresh token is even more dangerous than a stolen access token.
An attacker with a stolen access token is usually limited by that token's expiration time.
An attacker with a valid refresh token may be able to request new access tokens.
For example:
Stolen Refresh Token
↓
Authorization Server
↓
New Access Token
So the purpose of refresh tokens is not to create a credential that cannot be stolen.
The goal is to keep the more sensitive credential less exposed and better protected.
Why Is the Access Token Short-Lived but the Refresh Token Longer-Lived?
The access token may be used in a large number of requests:
GET /profile
Authorization: Bearer ACCESS_TOKEN
GET /orders
Authorization: Bearer ACCESS_TOKEN
POST /comments
Authorization: Bearer ACCESS_TOKEN
It lives on a high-traffic path.
A refresh token, in a well-designed system, is used only when a new access token is needed.
For example:
Client
│
│ Refresh Token
▼
Authorization Server
│
│ New Access Token
▼
Client
So ideally:
Access Token
→ Frequent usage
→ Greater exposure
→ Short lifetime
Refresh Token
→ Limited usage
→ Stronger protection
→ Longer lifetime
What If Both Access and Refresh Tokens Are Stored in Cookies?
This is a very important question.
Suppose both tokens are stored like this:
access_token=AAA;
HttpOnly;
Secure;
Path=/
refresh_token=RRR;
HttpOnly;
Secure;
Path=/
The browser may then send both cookies with ordinary API requests.
For example:
GET /api/profile
and the browser might send:
Cookie:
access_token=AAA;
refresh_token=RRR;
Then:
GET /api/products
and again both tokens are sent.
In this design, one of the main benefits of separating access tokens from refresh tokens is weakened, because the refresh token is unnecessarily exposed to every backend request.
A Better Cookie Design
Cookie scope can be restricted.
For example:
Set-Cookie: access_token=AAA;
HttpOnly;
Secure;
Path=/api
And:
Set-Cookie: refresh_token=RRR;
HttpOnly;
Secure;
Path=/auth/refresh
Now when the browser sends:
GET /api/profile
the access token may be sent to the API path.
But the refresh token is not in scope for ordinary API endpoints.
When the access token expires, the client can call:
POST /auth/refresh
and the refresh token is used only there.
Architecturally:
Access Token
↓
Resource Server / API
Refresh Token
↓
Authorization Server / Refresh Endpoint
This difference is often more important than simply giving the two tokens different expiration times.
What Does HttpOnly Actually Do?
You often hear that authentication tokens should be placed inside HttpOnly cookies.
But it is important to understand exactly what HttpOnly means.
HttpOnly does not mean the cookie will not be sent to the server.
The browser still sends the cookie automatically with matching requests.
HttpOnly only prevents normal browser JavaScript from directly reading the cookie value.
For example, JavaScript should not be able to simply retrieve it through:
document.cookie
So:
HttpOnly
↓
Prevents normal JavaScript access to Cookie value
What Does Secure Do?
If a cookie has the:
Secure
attribute, the browser sends it only over HTTPS.
So:
Secure
↓
Cookie only over HTTPS
What Does SameSite Do?
SameSite controls how cookies behave in cross-site requests.
It is one of the mechanisms that can help reduce certain forms of CSRF attacks.
Conceptually:
SameSite
↓
Controls cross-site cookie behavior
What Do Path and Domain Do?
Path determines which URL paths the cookie can be sent to.
Domain determines which hosts or domains the cookie is valid for.
So:
HttpOnly
→ JavaScript access
Secure
→ HTTPS only
SameSite
→ Cross-site behavior
Path / Domain
→ Where the Cookie is sent
Each property solves a different security problem.
Access Tokens and Refresh Tokens Do Not Have the Same Authority
Even if both are tokens, they serve different purposes.
The access token is used against a Resource Server:
Access Token
↓
API
↓
GET /orders
POST /comments
GET /profile
The refresh token should not be accepted as a normal API credential.
For example, this should not work:
GET /orders
Authorization: Bearer REFRESH_TOKEN
The Resource Server should reject it.
A refresh token exists only to obtain new access tokens:
Refresh Token
↓
Authorization Server
↓
Access Token
So the difference is not only:
Access Token → 15 minutes
Refresh Token → several days
Their audience and intended usage are also different.
Refresh Token Rotation
One important technique for improving refresh token security is Refresh Token Rotation.
Suppose the client initially has:
RT1
The client uses it:
RT1
↓
Authorization Server
↓
Access Token + RT2
The server invalidates RT1.
Now:
RT1 → Invalid
RT2 → Valid
Next time:
RT2
↓
Authorization Server
↓
Access Token + RT3
Then:
RT2 → Invalid
RT3 → Valid
Each refresh token is therefore intended to be used only once.
If an old token such as RT1 later appears again:
Attacker
↓
RT1
↓
Server
↓
This token was already used
that may indicate token theft.
The server may then revoke the session or the related family of refresh tokens.
These ideas are commonly referred to as Refresh Token Rotation and Reuse Detection.
What If an Attacker Steals Both Tokens?
That is a serious situation.
Access and refresh tokens are not magical security mechanisms.
Security is usually about reducing the probability of compromise and limiting the impact when something goes wrong.
If an attacker obtains both credentials, they may be able to use the current access token and also request new ones using the refresh token.
That is why refresh tokens normally receive stronger protection.
Typical protections include:
Secure Storage
Limited lifetime
Rotation
Revocation
Reuse Detection
Appropriate Cookie scope
BFF: What If the Browser Stores No Tokens at All?
Some web applications use another architecture.
Instead of storing access and refresh tokens directly in the browser, the backend stores them.
The browser only holds a session cookie.
For example:
Browser
│
│ Session Cookie
▼
Backend / BFF
│
├── Access Token
└── Refresh Token
│
▼
APIs / Authorization Server
In this model:
Browser
❌ Access Token
❌ Refresh Token
Backend
✅ Access Token
✅ Refresh Token
This type of pattern is commonly called a Backend for Frontend, or BFF.
There is no rule saying that access tokens and refresh tokens must always be stored directly inside browser cookies.
What Is JWT?
JWT stands for:
JSON Web Token
JWT is not an authentication protocol.
It is a standardized token format.
This distinction is important.
JWT ≠ Authentication Protocol
JWT = Token Format
JWT Structure
A JWT usually contains three parts:
xxxxx.yyyyy.zzzzz
That means:
Header.Payload.Signature
For example:
eyJhbGciOiJIUzI1NiJ9
.
eyJzdWIiOiIxMjMifQ
.
SflKxwRJSMeKK...
Header
The header usually contains metadata about the token.
For example:
{
"alg": "HS256",
"typ": "JWT"
}
Payload
The payload contains claims.
For example:
{
"sub": "12345",
"name": "Ali",
"role": "admin",
"exp": 1770000000
}
Information inside a JWT is commonly called claims.
For example:
sub
usually represents the Subject.
And:
exp
represents the expiration time.
Signature
The signature helps the receiver detect whether the token has been modified without authorization.
Conceptually:
Header
+
Payload
+
Secret / Private Key
↓
Signature
Suppose an attacker changes:
"role": "user"
to:
"role": "admin"
If signature validation is performed correctly, the modified token will no longer be valid.
Is JWT Data Secret?
Not necessarily.
This is one of the most common misunderstandings about JWT.
The payload of a normal JWT can usually be decoded.
Therefore, sensitive information should not be considered protected simply because it is inside a JWT.
For example, this would be a bad idea:
{
"password": "secret",
"creditCard": "..."
}
A signature primarily protects integrity:
Has the data been modified?
It does not necessarily provide confidentiality:
Can anyone see the data?
In other words:
A signed JWT is not necessarily an encrypted JWT.
What Is the Benefit of JWT?
A JWT can carry useful information inside the token itself.
For example:
{
"userId": 42,
"role": "admin"
}
After properly validating the token, a Resource Server may be able to use some of those claims directly.
This is one reason JWTs are common in distributed and API-based systems.
JWT and Logout
Suppose a JWT is valid until 18:00.
The user logs out at 17:00.
If the system is fully stateless, the JWT may still be cryptographically valid until 18:00.
For example:
17:00 → User logs out
JWT
↓
Still valid until 18:00
This can make revocation more complicated than with fully server-side sessions.
Possible approaches include:
Short-lived Access Tokens
Revocation mechanisms
Token deny lists in some architectures
Refresh Token revocation
Session tracking
So statelessness is not automatically better. It introduces trade-offs.
What Is OAuth?
OAuth is one of the most misunderstood terms in authentication-related discussions.
OAuth is primarily designed for Delegated Authorization.
In other words:
How can we allow an application to access a limited set of our resources without giving that application our password?
The Password-Sharing Problem
Suppose a photo-printing application wants access to your photos.
A terrible design would be:
Google Username?
Google Password?
The user would be giving their full Google credentials directly to the third-party application.
That is dangerous.
OAuth addresses this problem.
Instead of sharing the password, the application receives a limited access token.
Conceptually:
Photo App
↓
Authorization Server
↓
User gives permission
↓
Photo App receives limited access
The application never needs to receive the user's original account password.
Main Roles in OAuth
OAuth has four important roles.
Resource Owner
Usually the user.
For example:
Ali
The user owns or controls access to the resource.
Client
The application requesting access.
For example:
Photo Printing App
Authorization Server
The system that manages authorization and issues tokens.
The user interacts with this server for authentication and consent.
Resource Server
The server that stores or exposes the protected resource.
For example:
Photos API
The Resource Server validates the access token before granting access to the resource.
A Simplified OAuth Flow
The client wants access to the user's photos.
The user is redirected to the Authorization Server.
They may see something like:
PhotoApp wants permission to:
✓ Read your photos
The user clicks:
Allow
In a common flow, the client first receives an Authorization Code.
Then:
Authorization Code
↓
Authorization Server
↓
Access Token
The client now has an access token and can call the Resource Server:
GET /photos
Authorization: Bearer ACCESS_TOKEN
The Resource Server validates the token and returns the requested resource if access is allowed.
What Is a Scope?
OAuth allows access to be limited.
For example, a client may receive permission to only read photos:
photos.read
but not delete them.
Other scopes might be:
contacts.read
calendar.write
profile.read
A scope describes what type of access a client requests or receives.
This is closely related to a fundamental security principle:
Principle of Least Privilege
Meaning:
Grant only the minimum access that is actually required.
Is OAuth for Login?
OAuth is primarily about authorization.
Its core question is closer to:
What can this application access?
not necessarily:
Who exactly is this user?
For authentication and identity, another layer called OpenID Connect is commonly used.
OpenID Connect, or OIDC
OpenID Connect, usually abbreviated as OIDC, is an identity layer built on top of OAuth.
In very simplified terms:
OAuth
+
Identity Layer
=
OpenID Connect
OIDC is widely used for scenarios such as login and Single Sign-On.
Access Token vs. ID Token
With OIDC, Access Tokens and ID Tokens should be treated as different things.
Access Token
An Access Token is for the API or Resource Server:
Client
↓
Access Token
↓
API
For example:
Authorization: Bearer ACCESS_TOKEN
ID Token
An ID Token is intended for the client and contains information about authentication and identity.
An ID Token is typically a JWT.
For example:
{
"sub": "983725",
"iss": "https://identity.example",
"aud": "my-app",
"exp": 1770000000
}
After proper validation, the client can determine which subject was authenticated.
Access Token vs. ID Token
In short:
Access Token
→ API Access
ID Token
→ Authentication / Identity information
They should not be used interchangeably.
How Does “Login with Google” Fit Into This?
When a user clicks something like:
Continue with Google
the application redirects the user to an Identity Provider.
The user authenticates there.
Through a standardized flow, the application receives the information it needs and can establish a local session for the user.
OpenID Connect commonly plays the identity role in this kind of flow.
So, very simply:
OAuth
→ Delegated Authorization
OIDC
→ Authentication + Identity
What Is MFA?
MFA stands for:
Multi-Factor Authentication
The goal of MFA is to avoid relying on a single credential such as a password.
For example:
Password
+
Second Factor
Authentication Factors
Authentication factors are commonly divided into several categories.
Something You Know
Something the user knows:
Password
PIN
Something You Have
Something the user possesses:
Phone
Authenticator Device
Hardware Security Key
Something You Are
A physical or biometric characteristic:
Fingerprint
Face
Is Password + PIN MFA?
Not necessarily.
Both belong to the same factor category:
Password
+
PIN
Both are:
Something You Know
True MFA generally combines independent factors.
For example:
Password
+
Security Key
Here one factor is Something You Know, and the other is Something You Have.
OTP
A common second factor is a One-Time Password.
The user first enters the password.
Then the system asks:
Enter your 6-digit code
An authenticator application might display:
418239
Now, even if an attacker knows the password, they still need the second factor.
SMS can also be used as a second factor, although stronger options such as authenticator applications and hardware security keys also exist.
What Is an RFC?
When discussing authentication and internet protocols, you will often see references such as:
RFC 7519
RFC 6750
RFC 6749
RFC stands for:
Request for Comments
The name can sound informal, but RFCs are very important technical documents used on the internet.
Many internet protocols, formats, and standards are precisely documented through RFCs.
For example:
RFC 7519 → JWT
RFC 6750 → Bearer Token Usage
RFC 6749 → OAuth 2.0
Not every RFC is necessarily a final Internet Standard; RFCs have different categories.
But in practical terms, they can be thought of as official technical documents that precisely define protocol and standard behavior.
What Is the IETF?
Many important RFCs are published through processes associated with the IETF.
IETF stands for:
Internet Engineering Task Force
A simplified view looks like this:
Experts / Working Groups
↓
Technical Specification
↓
RFC
↓
Implementations
These standards allow implementations from different companies and programming languages to work together.
For example, a Java backend and a Go service can both understand the same JWT structure because they follow the same standardized format.
How All of These Concepts Fit Together
Now we can connect all the pieces.
Suppose we have an online store.
The user first enters:
Username + Password
These credentials are used for authentication.
For additional security, the system may require:
Password
+
Authenticator Code
That is MFA.
After authentication, the system may create a session:
Session
↓
Session ID
↓
Cookie
Or it may use a token-based architecture and issue an Access Token:
Access Token
The client may present that token as a Bearer token:
Authorization: Bearer <token>
The access token itself may be a JWT:
Bearer
↓
JWT Access Token
But it does not have to be a JWT; it may also be an opaque token.
If the access token is short-lived, the client may also receive a Refresh Token:
Refresh Token
↓
Authorization Server
↓
New Access Token
If a third-party application needs limited access to a user's resources, OAuth may be involved.
If the system needs standardized login and identity, OpenID Connect may be involved.
And once authentication succeeds, authorization determines what the user or client is actually allowed to do.
A Useful Mental Model
You can think of many of these concepts like this:
Authentication
│
┌─────────────┼─────────────┐
│ │ │
Password MFA OIDC
│
▼
User Verified
│
┌─────┴─────┐
│ │
Session Token
│ │
Cookie ┌───┴─────┐
│ │
Opaque JWT
│
▼
Authorization: Bearer ...
OAuth can be viewed on another axis:
OAuth
│
▼
Delegated Authorization
│
├── Access Token
├── Scope
└── Third-party Access
Common Misconceptions
There are several common mistakes worth avoiding.
JWT is not a login method.
JWT = Token Format
Bearer and JWT are not the same thing.
Bearer = How a token is presented
JWT = A possible token format
OAuth by itself is not the same thing as login.
OAuth = Delegated Authorization
OIDC adds identity and authentication concepts on top of OAuth.
OIDC = Identity Layer
Cookie and Session are not the same thing.
Cookie = Browser mechanism
Session = Server-side authentication state
HttpOnly does not mean the cookie is not sent.
HttpOnly
→ JavaScript cannot normally read the cookie
Browser
→ Can still send it automatically
A Refresh Token is not inherently impossible to steal.
A refresh token is still a sensitive credential.
The reason for having separate Access and Refresh Tokens is to separate a frequently used, short-lived credential from a more sensitive, less frequently used credential.
Important Security Practices
Choosing JWT, OAuth, or cookies does not automatically make a system secure.
Implementation matters much more than the name of the technology being used.
In general:
- Always use HTTPS for authentication data and tokens.
- Never store passwords in plain text.
- Use appropriate password hashing algorithms.
- Keep access tokens as short-lived as reasonably possible.
- Protect refresh tokens more carefully.
- Do not send refresh tokens to every API endpoint when they are not needed.
- Use Refresh Token Rotation and Reuse Detection when appropriate.
- Follow the Principle of Least Privilege for scopes and permissions.
- Do not store sensitive tokens in unsafe client-side locations.
- In web applications, configure sensitive cookies appropriately using attributes such as
HttpOnly,Secure, andSameSite, depending on the architecture. - Avoid overly broad Cookie
PathandDomainsettings. - Use MFA for sensitive accounts.
- Design logout, revocation, and expiration from the beginning rather than adding them at the end.
Conclusion
If we reduce the whole topic to a few important ideas:
Authentication answers who you are.
Authorization determines what you are allowed to do.
Username and Password are one of the simplest ways to prove identity, but passwords must be stored securely using password hashing.
Session usually stores login state on the server, while a Cookie can store and transmit a session identifier in the browser.
Basic Auth sends username and password through the HTTP Authorization header, and Base64 provides no real encryption.
API Keys are commonly used to identify a client, application, or project.
Token-Based Authentication replaces repeated password transmission with a token.
Bearer describes a common way of presenting a token, where possession of the token is enough to use its authority.
Access Tokens are used to access Resource Servers and APIs.
Refresh Tokens are used to obtain new Access Tokens and should be used in a much more limited and protected way.
JWT is only a token format, and a signed JWT is not necessarily encrypted.
OAuth is primarily designed for delegated authorization.
OpenID Connect adds an identity layer on top of OAuth and is commonly used for authentication and login.
MFA reduces dependence on a single password by requiring multiple independent authentication factors.
And perhaps the most important lesson is:
Authentication security does not come from choosing a technology with the right name. It comes from architecture, secure credential storage, limited exposure, least privilege, expiration, revocation, and correct implementation.