What this note is really about
Authentication and authorization are discussed constantly in software, but they are often mixed together so casually that people lose the real distinctions.
You will hear things like:
- “add auth”
- “protect the API”
- “check permissions”
- “log the user in”
Those may involve related mechanisms, but they are not all the same problem.
This note is about:
- what authentication actually is
- what authorization actually is
- how they differ
- what kinds of software need them
- the main implementation patterns used today
- the tools and frameworks people rely on
- what it would take to implement them yourself manually
This topic is important because authentication and authorization are not optional details in serious software.
They are part of:
- security
- user identity
- system boundaries
- data protection
- operational trust
- compliance in some domains
So the goal here is not “memorize terms.”
The goal is to be clear-headed about the actual security boundary being designed.
The fundamental distinction
The cleanest starting point is this:
Authentication
Authentication answers:
Who are you?
It is the process of establishing identity.
Examples:
- proving you are a specific user
- proving this service is a trusted service
- proving this device session belongs to a known account
Authorization
Authorization answers:
What are you allowed to do?
It is the process of deciding whether an authenticated identity may access a resource or perform an action.
Examples:
- can this user read this document?
- can this admin delete that account?
- can this service call that internal endpoint?
- can this customer see only their own orders?
Short rule
Authentication is about identity.
Authorization is about permissions.
That distinction is the foundation for everything else.
Why the distinction matters
A system can authenticate correctly and still authorize badly.
Examples:
- the user is correctly logged in, but can access another user’s data
- the API knows which service is calling, but that service has too many privileges
- the admin role is granted too broadly
Likewise, a system can have authorization rules conceptually, but if authentication is weak, those rules are being applied to an untrusted or spoofable identity.
So strong systems need both:
- reliable identity establishment
- correct permission enforcement
If either half is weak, the boundary is weak.
Not all software needs the same level of auth
Different kinds of software need different identity and permission models.
Personal offline tools
Some software has no real user separation and may need little or no formal auth.
Examples:
- a local single-user utility
- a private script on your own machine
Consumer applications
These usually need:
- user accounts
- login
- password reset
- session management
- account recovery
- user-specific data protection
Examples:
- e-commerce
- social apps
- productivity apps
Enterprise software
These often need:
- organization-level identity
- employee login
- group and role mapping
- auditability
- admin control
- single sign-on
Examples:
- HR systems
- finance tools
- internal dashboards
- SaaS products for companies
Public APIs and developer platforms
These often need:
- API keys
- OAuth flows
- scopes
- service-to-service trust
- rate limits
- tenant isolation
Internal microservices
These need:
- service identity
- secure communication
- machine credentials
- internal authorization boundaries
High-risk software
Banking, healthcare, identity systems, and admin platforms often need stronger controls such as:
- multi-factor authentication
- step-up verification
- stronger audit trails
- fine-grained authorization
- shorter token lifetimes
- anomaly detection
So the right auth model depends heavily on the software context.
Identity is broader than “user with password”
People often think authentication means:
- username
- password
That is only one common case.
Identities in software can include:
- human users
- admin users
- service accounts
- applications
- devices
- tenants or organizations
- external partners
This matters because a secure system often has to authenticate more than one type of actor.
For example:
- a browser user logs in
- a mobile app holds tokens
- a backend service calls another service
- a scheduled job runs under a service identity
These are different identities with different trust models.
The main authentication factors
Authentication methods are often described in terms of what the subject proves.
Something you know
Examples:
- password
- PIN
- security answer
Something you have
Examples:
- phone receiving OTP
- authenticator app
- hardware key
- smart card
Something you are
Examples:
- fingerprint
- face recognition
- other biometrics
Modern security often combines multiple factors.
That is multi-factor authentication or MFA.
MFA matters especially when:
- accounts are valuable targets
- privileges are high
- compliance requirements exist
- phishing risk is high
Passwords: still common, but not enough by themselves
Passwords remain widely used because they are familiar and easy to deploy.
But passwords have major weaknesses:
- reuse across sites
- phishing
- weak user choices
- leaks from compromised services
- credential stuffing attacks
So modern best practice is not “never use passwords.”
It is:
- if passwords exist, handle them correctly
- often combine them with MFA
- increasingly support better login methods where possible
How passwords should be stored
This is one of the most important fundamentals.
You should never store plain-text passwords.
You should also not store them using simple fast hashes such as:
- plain SHA-256
- plain MD5
- plain SHA-1
Why?
Because password storage needs protection against offline brute-force attacks if the credential database is leaked.
Modern password storage uses:
- slow password hashing algorithms
- salting
- configurable work factors
Important names include:
- Argon2
- bcrypt
- scrypt
- PBKDF2
These are designed for password hashing, unlike ordinary fast cryptographic hashes.
The basic model is:
- generate a unique salt
- hash the password with a password-hashing algorithm
- store the salt and resulting hash
- on login, recompute and compare
That is a minimum baseline for password-based systems.
Sessions: the classic web model
One of the oldest and still very common patterns is:
- user logs in
- server verifies credentials
- server creates a session
- client stores a session identifier, often in a cookie
- future requests present that session identifier
- server looks up session state and recognizes the user
This is the classic session-based authentication model.
Important features:
- the server keeps session state
- the client usually stores only a session identifier
- session invalidation is straightforward on the server side
This remains strong and practical for many web applications.
Cookies and browser-based auth
In browser-oriented systems, cookies remain a major tool.
Why?
Because browsers naturally support them for request continuity.
Security-related cookie attributes matter:
HttpOnlySecureSameSite
These help reduce risks such as:
- script access to session cookies
- sending cookies over insecure transport
- certain cross-site request forgery patterns
A lot of practical browser auth is really session management plus safe cookie handling.
Tokens: the stateless-friendly model
Another common modern pattern is token-based authentication.
Instead of the server always looking up a session by ID, the client presents a token proving identity or authorization context.
Common token concepts include:
- access token
- refresh token
- ID token in some identity protocols
A token may contain claims such as:
- user identifier
- issuer
- audience
- expiration
- scopes
- roles
But a token is only useful if:
- it is issued securely
- it is validated correctly
- its lifetime and revocation model are understood
Token-based systems are common in:
- SPAs
- mobile apps
- APIs
- service-to-service communication
JWTs: common, useful, and often misunderstood
One widely used token format is the JWT:
- JSON Web Token
A JWT can carry signed claims and be verified by the receiver.
Benefits:
- portable
- standardized
- can work well across services
Common misunderstandings:
- “JWT means secure by default”
- “JWT means no server state is ever needed”
- “JWT is always the best choice”
None of those are automatically true.
Important realities:
- token contents are not secret just because the token is signed
- long-lived tokens are risky
- revocation can be harder than with server sessions
- audience, issuer, signature, expiry, and algorithm validation must be correct
JWTs are a tool, not a security strategy by themselves.
OAuth 2.0: delegation, not just login
OAuth 2.0 is one of the most important names in modern auth, but many people misunderstand it.
OAuth is fundamentally about:
delegated authorization
That means one application can obtain limited access to resources on behalf of a user or client, without directly sharing the user’s password with every application.
This is why OAuth is central for:
- third-party integrations
- APIs
- delegated access
- platform ecosystems
OAuth by itself is not mainly “who is the user?” in the identity sense.
It is about delegated access grants.
OpenID Connect: identity on top of OAuth
If OAuth is mainly about delegated authorization, OpenID Connect or OIDC adds identity-layer concepts on top of that foundation.
OIDC is commonly used for:
- user login through an identity provider
- single sign-on
- standard identity claims
So a practical summary is:
- OAuth 2.0: delegated authorization framework
- OpenID Connect: authentication/identity layer built on top of OAuth-style flows
This is one of the most important conceptual distinctions in modern software auth.
Single sign-on
In enterprise and platform environments, users often should not manage separate credentials for every system.
That leads to single sign-on or SSO.
With SSO:
- one identity provider handles primary login
- multiple applications trust that provider
- users authenticate once and gain access to multiple systems according to policy
This helps with:
- usability
- centralized policy
- employee lifecycle management
- MFA enforcement
- reduced password sprawl
Common enterprise identity providers support:
- SAML
- OAuth 2.0
- OpenID Connect
- directory integration
API keys
For some use cases, especially machine-to-machine or developer-platform access, APIs use API keys.
An API key is usually:
- a secret string identifying a client or application
- presented with requests
This can be useful for:
- simple platform usage
- quota enforcement
- identifying calling applications
But API keys are limited.
They are usually weaker than full delegated identity systems because:
- they are often long-lived
- they usually represent the application, not a human user
- they can be leaked
- they often provide coarse access control
So API keys are practical, but not sufficient for every security model.
Service-to-service authentication
Modern distributed systems often need services to authenticate each other.
This is not browser login.
This is machine identity.
Common approaches include:
- mTLS
- signed tokens
- workload identity systems
- cloud IAM-based service identity
- client certificates
Why this matters:
Inside a network, you still need trust boundaries.
“Internal” does not mean “safe by default.”
Service identity is a major part of modern platform security.
Authorization models
Once identity is established, the system must decide what that identity can do.
There are several important authorization models.
Role-based access control
RBAC assigns permissions through roles such as:
- user
- moderator
- admin
- billing-manager
This is common because it is simple and understandable.
Good for:
- many enterprise systems
- admin panels
- coarse to medium-grained permissions
Weakness:
- can become messy if too many exceptions accumulate
Permission-based or capability-based models
Instead of only broad roles, systems may use explicit permissions such as:
order.readorder.cancelinvoice.approveuser.delete
This supports finer control.
Attribute-based access control
ABAC makes decisions based on attributes such as:
- user department
- resource owner
- tenant
- data classification
- time or location
This can be more expressive, but it is also more complex.
Policy-based authorization
Some systems define reusable policies that evaluate multiple conditions together.
This is common in modern frameworks because it scales better than sprinkling raw role checks everywhere.
Relationship-based authorization
Some systems base authorization on relationships such as:
- owner
- manager
- collaborator
- member of organization
This matters a lot in document-sharing, SaaS, and collaborative systems.
In practice, real systems often combine multiple models.
Authentication does not imply authorization
This point deserves repetition.
A user being authenticated does not mean they should access everything their account can technically reach through URLs or IDs.
Examples:
- a user should see only their own invoices
- a tenant admin should see only data within their tenant
- a support staff member may read but not modify
- a service can call billing APIs but not HR APIs
Strong authorization is usually contextual:
- who is the caller?
- what resource is involved?
- what action is being attempted?
- under what tenant, organization, or ownership rule?
This is why authorization checks must be close to domain meaning, not only route-level decoration.
Multi-tenant software
Many modern systems are multi-tenant:
- one software platform serves many organizations or customer accounts
That creates a critical authorization concern:
tenant isolation
Even a properly authenticated user must usually be limited to:
- their tenant
- their organization’s data
- their authorized scope within that tenant
Multi-tenant authorization bugs can be severe because they risk cross-customer data exposure.
So auth design in SaaS systems often includes:
- tenant-scoped identities
- tenant claims
- tenant-aware queries
- tenant-aware authorization rules
Different software types use auth differently
This is worth seeing side by side.
Traditional server-rendered web app
Often uses:
- session cookies
- server-side session storage
- form login
- CSRF protection
SPA plus backend API
Often uses:
- token-based auth
- OAuth/OIDC login via identity provider
- short-lived access tokens
- refresh tokens or silent re-auth patterns
Mobile apps
Often uses:
- token-based auth
- secure credential or token storage on device
- OAuth/OIDC flows through browser or system web auth
Internal enterprise systems
Often uses:
- SSO
- corporate identity provider
- MFA
- role or group-based authorization
Public developer APIs
Often uses:
- API keys for simple clients
- OAuth for delegated user access
- scopes
- quotas
- per-client limits
Microservices and platform systems
Often uses:
- service identity
- internal tokens or mTLS
- policy-based authorization between services
So “how auth works” changes significantly depending on the software architecture.
Best practices for authentication today
At a broad modern level, strong practice usually includes:
- use proven identity standards where appropriate
- do not build password storage casually
- hash passwords with proper password-hashing algorithms
- support MFA where risk justifies it
- use short-lived tokens where tokens are used
- secure refresh mechanisms carefully
- validate all token claims properly
- use HTTPS everywhere
- protect cookies properly if cookie-based sessions are used
- design account recovery carefully
- log security-relevant events
- rotate secrets and keys
- minimize credential exposure
The key pattern is:
prefer well-understood security building blocks over homemade cryptographic invention
Best practices for authorization today
Strong authorization practice usually includes:
- enforce least privilege
- keep permissions explicit
- avoid spreading ad hoc checks randomly through the codebase
- centralize policy logic where practical
- authorize at the right level of domain meaning
- include tenant and ownership rules where relevant
- make admin privileges narrow and auditable
- review default access carefully
- log sensitive actions
- test negative cases, not only happy paths
Authorization failures are often logic failures more than cryptographic failures.
So discipline and clear policy modeling matter greatly.
Manual implementation: what it means if you do it yourself
If you implemented authentication and authorization manually with your own code and no auth framework, the minimum correct path would look something like this: define a user identity model, build credential registration and login flows, hash passwords with a proper password-hashing algorithm such as Argon2, bcrypt, scrypt, or PBKDF2 using per-password salts, verify credentials during login, issue either a secure server-side session or a signed token with strict expiration and claim validation rules, protect transport with HTTPS, implement logout and credential reset flows, add MFA if needed, and then build an authorization layer that checks roles, permissions, ownership, tenant boundaries, and action-specific policies before executing protected operations. This is very possible in principle, but it is easy to get wrong in edge cases such as password recovery, token revocation, CSRF, refresh logic, secret rotation, privilege escalation, and auditability. That is why many teams rely on established protocols and battle-tested libraries rather than hand-rolling the entire system.
Why people use frameworks and services now
Authentication and authorization are easy to underestimate.
What looks simple at first quickly expands into:
- login UI
- password hashing
- email verification
- password reset
- MFA enrollment
- token issuance
- token refresh
- session revocation
- audit trails
- federation with external identity providers
- SSO
- permissions and policy evaluation
- admin management
Because of that complexity, many teams now prefer:
- libraries for lower-level auth primitives
- framework-integrated auth middleware
- external identity providers
- managed auth platforms
This is not laziness.
It is often good security engineering.
You still need to understand the concepts, but you should not reinvent everything carelessly.
Tools and frameworks: broad categories
Instead of memorizing one product list only, it is better to understand the major categories.
1. Framework-level authentication and authorization systems
Most major web frameworks provide built-in or ecosystem-supported support for:
- login middleware
- session handling
- policy checks
- role checks
- bearer token validation
Examples by ecosystem include:
- ASP.NET Core Identity and ASP.NET Core authorization policies
- Spring Security in Java
- Django auth in Python
- Laravel auth systems in PHP
- Express or NestJS middleware ecosystems in Node.js
- Rails authentication and authorization libraries in Ruby
These help because they integrate auth with:
- routing
- middleware
- request context
- session or token handling
2. Standards-based identity libraries
These help applications work with:
- OAuth 2.0
- OpenID Connect
- JWT validation
- SAML in some environments
They are used when the system needs:
- external login
- SSO
- delegated authorization
- token issuance or validation
3. Managed identity providers
Many teams use dedicated identity services such as:
- Auth0
- Okta
- Microsoft Entra ID
- Amazon Cognito
- Keycloak
- Clerk
- Firebase Authentication
- Supabase Auth
These provide varying combinations of:
- user directories
- login flows
- social login
- enterprise SSO
- MFA
- token issuance
- user management
The advantage is reduced implementation burden.
The tradeoff is dependency on platform conventions, pricing, and integration boundaries.
4. Access control and policy engines
For complex authorization, some systems use policy engines or dedicated authorization tools.
Important names include:
- OPA / Open Policy Agent
- Zanzibar-inspired relationship systems
- Cedar-inspired policy models in some ecosystems
These are useful when authorization is:
- complex
- cross-service
- highly policy-driven
- relationship-rich
5. Secrets and key management systems
Auth also depends on managing:
- signing keys
- client secrets
- encryption material
So infrastructure tools such as:
- cloud secret managers
- HSM-backed key systems
- Vault-style secret stores
are part of the broader auth story too.
Frameworks do not remove responsibility
Using a framework or identity provider does not mean security is solved automatically.
You still must decide:
- what identities exist
- what trust boundaries exist
- what the token audience should be
- what privileges each role or scope has
- how tenant isolation works
- what should be logged
- what recovery flows are allowed
- what session duration is acceptable
Frameworks reduce implementation risk in many areas, but they do not replace security design judgment.
Session-based vs token-based today
People often ask which one is “best.”
That is the wrong question.
The better question is:
“Which model fits this system and threat model?”
Session-based auth is often strong for:
- traditional web apps
- browser-based systems
- systems where server-controlled revocation is important
Token-based auth is often strong for:
- APIs
- mobile clients
- service-to-service systems
- federated identity environments
Many modern architectures use a mix:
- browser login via identity provider
- backend session or token handling
- access tokens for APIs
- refresh tokens or re-auth flows
The correct design depends on architecture and risk.
Common mistakes
Weak auth systems often show one or more of these problems:
- storing plain-text passwords
- using fast hashes for passwords
- confusing authentication with authorization
- treating “logged in” as “fully trusted”
- embedding too much permanent trust into long-lived tokens
- weak tenant isolation
- no MFA for high-value accounts
- insecure password reset flows
- role checks scattered randomly through code
- no audit trail for sensitive actions
- trusting client-supplied claims without server validation
- exposing internal admin APIs too broadly
These are not edge details.
They are common sources of serious security failures.
A practical design workflow
When designing auth for a system, a useful sequence is:
- Identify the actors: users, admins, services, devices, partners.
- Identify the resources and actions that need protection.
- Decide the trust model: local accounts, external identity provider, SSO, service identity, or a mix.
- Choose the authentication mechanism appropriate to the software type.
- Choose the authorization model: roles, permissions, policies, relationships, tenant rules.
- Define session or token lifetime, revocation, recovery, and MFA strategy.
- Secure secrets, signing keys, and transport.
- Add audit logging, rate limiting, and failure monitoring.
- Test not only valid access, but denied access and boundary violations.
- Revisit the design as the system becomes more distributed or more security-sensitive.
This workflow is much more valuable than “just plug in a login package.”
The most important conceptual thread
If you want one flow that ties the whole topic together, it is this:
Authentication establishes identity, while authorization decides allowed actions. Modern software must often authenticate not only users, but also services, devices, and organizations. Different software types use different mechanisms: web apps often use sessions and cookies, APIs and mobile systems often use tokens, enterprise systems often use SSO and identity providers, and distributed backends often use service identity. Authorization then applies roles, permissions, policies, ownership, and tenant boundaries to those identities. Today, most serious systems rely on standard protocols, framework support, and managed identity tooling for the heavy lifting, while still requiring application-specific authorization logic, careful policy design, and strong operational practices such as MFA, secure secret handling, audit logging, and least privilege.
What you should come away knowing
You should leave this topic with these ideas clearly separated:
- Authentication is about identity.
- Authorization is about permissions.
- Many software systems need both, but not all in the same form.
- Passwords are only one authentication method, and must be stored properly if used.
- Sessions, cookies, tokens, OAuth, and OIDC solve different parts of the problem.
- API keys, service identity, and SSO matter in different architectures.
- Authorization models include roles, permissions, policies, attributes, and relationships.
- Tenant isolation and ownership checks are critical in many modern systems.
- Frameworks and identity providers help a lot, but they do not replace security thinking.
- The hardest part in many systems is not login itself, but getting authorization boundaries correct.
Bottom line
Authentication and authorization are foundational security boundaries in software. Authentication proves who the caller is, and authorization determines what that caller may do. Different software types implement them differently depending on whether the system is a browser app, mobile app, API platform, internal enterprise product, or distributed backend. Modern practice usually combines established password hashing, sessions or tokens, standards such as OAuth and OpenID Connect, MFA where appropriate, and framework or managed identity support, while keeping authorization logic explicit, domain-aware, least-privileged, and carefully audited.