
Authentication: A Conceptual Guide for Software Engineers
What prompted this blog?
Authentication is something I set up on every system I work on. I typically use Better Auth for this because of the smooth developer experience and comprehensive documentation. However, I noticed that I find myself just copy-pasting the code provided by the documentation without wondering what happens under the hood.
On one hand, I find this to be a benefit. The framework provides an abstraction that takes care of the low-level details, allowing me to focus on building the application.

On the other hand, a lack of understanding these details makes it hard to debug issues if they arise in development, or worse, production. If a user is unable to log in, is it because I integrated the library wrong or did my application code mishandle something downstream?
So, I decided to take a peek behind the veil of what these authentication libraries/frameworks do to better develop my mental model for authentication.
What is authentication?
To put it succinctly, authentication seeks to answer the question "Who are you?", which comes in to stages:
- Identification - Claiming who you are (e.g. enter an email address)
- Verification - Proving your claim (e.g. enter the correct password for that email address)
Why care about this distinction? Because different attacks target different stages and, consequently, have different defenses! For example:
- Credential stuffing, where leaked credentials are used by attackers, targets identification as the attacker knows the claim and proof (email and password).
- Brute force attacks, where an attacker tries many passwords against a known account, targets verification as the attacker only knows the claim but not the proof, so they try to guess it.
How does this compare to authorization?
While authentication lets you know who a user is, authorization lets you know what that user is allowed to do. Authentication comes first since you can't decide what a user is allowed to do without first identifying who they are. However, it's important to note that authentication and authorization can fail independently!
For example, a system can have completely functional authentication but broken authorization. What would this look like? A valid user can log in correctly, while attackers can't, but they can access the data of another user. In other words, the login works fine but access control is failing.
The opposite is also possible. You could have airtight role checks, but if your session tokens are easy to steal or leak, an attacker can impersonate a legitimate user and perform destructive actions
What do we mean by multi-factor authentication?
Every authentication mechanism falls into one of the following categories, which we call factors:
Factor | What it means | Examples |
|---|---|---|
Knowledge | Something you know | Password, PIN, Security Questions |
Possession | Something you have | Email, Phone Number, Hardware Key |
Inherence | Something you are | Fingerprint, Face Scan |
The reason we care about this distinction is because each one identifies it's vulnerable to:
- Knowledge - Phishing or leaked in a database breach
- Possession - Can be stolen or swapped
- Inherence - Can't be rotated if compromised (you can't change your fingerprint!)
Multi-factor authentication simply refers to an authentication system that employs at least two mechanisms from different factors. Think of Google, which asks for a password (knowledge) and then a code sent to your email (possession) or a bank mobile application that requires a PIN (knowledge) and an OTP (possession).
By employing multiple factors of authentication, we improve security because compromising an account requires compromising multiple authentication mechanisms. Say that your bank application's database got compromised, leaking your PIN. Even with this information, attackers won't be able to get into your account because they'd still need the OTP sent to your phone. Although this isn't impossible, it makes it much more difficult to pull off since they need to carry out multiple types of attacks (leak database for password, steal phone for OTP).
You may think that an authentication system that employs two passwords or a password and a security question falls under multi-factor authentication (this is what I thought at least). However, this is not the case!
Although multiple authentication mechanisms are used (i.e. password + password, password + PIN), they fall under the same factor (knowledge). Multi-factor authentication requires the mechanisms to be from different factors.
What happens if an authentication system functions like this? An attacker can compromise both mechanisms simultaneously with a single attack! A phishing attack, or a database leak, can reveal your two passwords or password and security question.
How do I think about the authentication stack?
While learning more about authentication, I started to develop this mental model around it. It splits authentication into four distinct layers:
Layer | Function | Example |
|---|---|---|
L4: Access Control | Allow/deny operations based on business rules | RBAC, ABAC |
L3: Session Management | Maintain authentication state across requests | Cookies, JWT's |
L2: Credential Verification | Proving identity claims | Password Hashing |
L1: Transport Security | Securing data in transit via encryption | HTTPS, TLS |
In this stack, a layer can only be functional if the layers below it are functional as well:
- L2 without L1: Passwords are on the server, but they travel in plaintext over HTTP. An attacker on the network can intercept your request and read your password before it reaches your server for hashing.
- L3 without L2: Your system can issue sessions without a problem, but it never verifies the credentials of the user requesting a session. Anyone who claims to be
[email protected]` gets a valid session. - L4 without L3: Your role checks are airtight and properly implement business rules, but sessions can be easily stolen via attacks like XSS. To your system, the attacker is an admin.
On top of helping me consolidate authentication conceptually, I find this model practically useful when integrating auth libraries.
Layer | Responsibility | Handler |
|---|---|---|
L4: Access Control | Route protection, role checks, permission checks for specific resources | Application code |
L3: Session Management | Session creation, cookie management, issuance and refreshing of tokens | Auth library |
L2: Credential Verification | Password hashing, OAuth token exchange | Auth library |
L1: Transport Security | HTTPS, TLS certificates | Hosting platform/infrastructure (e.g. Coolify, Vercel, Cloudflare) |
I used to think that an auth library took care of everything. How I think about it now is that these auth libraries just handle layers 2 and 3. Layer 1 is handled by your infrastructure and layer 4 is handled by your business logic, implemented via your application code.
For example, a library might expose session.user.role via its API, but it doesn't enforce what routes that role can access or what operations that role can perform because it's your business logic that gives these roles meaning:
1// The library gives you the identity (L2-L3)2const session = await auth.getSession(request);34// Enforcement is YOUR code (L4)5if (session.user.role != "admin") {6 return new Response("Forbidden", { status: 403 });7}
How to debug authentication issues with this mental model?
I mentioned earlier that one of the reasons why I wanted to dive deeper into authentication was to figure out where to look when things go wrong. The mental model helps with this! Here are some examples:
What's the problem? | What layer failed? | How to fix? |
|---|---|---|
User A accessed User B's data | Access control (L4). Authentication worked as User A was on a valid session, but the system failed to check what he was trying to access. | Enforce role/permission checks in the application code. |
An attacker logged in as our system administrator | Credential verification (L2). The attacker input valid credentials, which may have been obtained via phishing or a leak. | Employ MFA by adding a second factor (e.g. face scan or OTP via SMS). |
User sessions are being hijacked without any login activity | Session management (L3). | Enforce stronger cookie configurations. |
Prior to this consolidation, each diagnosis would lead me down a rabbit whole trying to figure out where the issues were coming from. Now, each diagnosis maps to a layer, which points me in the direction of the fix.
What's the tldr?
Authentication is the process of identifying a user based on the claims they put forward and the proof behind them. This is distinct from authorization, which is the process of determining what kind of access an identified user has.
Authentication mechanisms come in three factors: knowledge (something you know), possession (something you have), and inherence (something you are). Multi-factor authentication systems employ authentication mechanisms from multiple distinct factors to prevent any single attack from compromising a user's account.
The mental model for the authentication stack consists of four layers: transport security, credential verification, session management, and access control. Auth libraries like Better Auth or Clerk handle layers two and three while layers one and four are to be handled by the hosting platform and the application code, respectively. Thinking of authentication with this model has helped me quickly identify potential fixes for diagnosed issues.