Authentication and Authorization
While often used interchangeably, authentication and authorization represent fundamentally different functions.
In simple terms, authentication is the process of verifying who a user is, while authorization is the process of verifying what they have access to.

Authentication
Determines whether users are who they claim to be
Challenges the user to validate credentials (for example, through passwords, answers to security questions, or facial recognition)
Usually done before authorization
Generally, transmits info through an ID Token
Authorization
Determines what users can and cannot access
Verifies whether access is allowed through policies and rules
Usually done after successful authentication
Generally, transmits info through an Access Token
Middleware
Middleware functions are functions that have access to the request object req
, the response object res
, and the next
function in the application's request-response cycle. The next
function is a function in the Express router that, when invoked, executes the middleware succeeding the current middleware.
You can compose middleware functions using techniques like functional programming. This can make your middleware code more reusable and maintainable.
Middleware functions can perform the following tasks:
Execute any code.
Make changes to the request and the response objects.
End the request-response cycle.
Call the next middleware in the stack.
If the current middleware function does not end the request-response cycle, it must call next()
to pass control to the next middleware function. Otherwise, the request will be left hanging.
Middleware functions can be used to perform a variety of tasks, such as:
Authentication and authorization: Verify that users are logged in and have the necessary permissions to access certain resources.
Logging and error handling: Log requests and handle errors gracefully.
Data validation: Ensure that incoming data is valid and meets the application's requirements.
Request and response manipulation: Modify the request object or response object before it is sent to the next middleware or route handler.
More info at https://expressjs.com/en/guide/writing-middleware.html
Authentication Strategies: A Comprehensive Comparison
Modern web applications employ various authentication strategies, each with distinct characteristics, benefits, and use cases. The following table provides a comparative overview of the most common authentication methods:
JWT (JSON Web Tokens)
• Stateless - no server-side storage needed
• Self-contained - carries user info
• Scalable across multiple servers
• Cross-domain friendly
• Mobile-friendly
• Cannot be invalidated before expiration
• Token size can grow with claims
• Vulnerable to XSS if stored in localStorage
• All tokens valid until expiration
• RESTful APIs
• Microservices architecture
• Single Page Applications (React, Vue, Angular)
• Mobile applications
• Examples: Spotify API, Auth0, Firebase Authentication
Session-based Authentication
• Server can invalidate sessions immediately
• Smaller cookie size
• More secure against token theft• Easy to implement logout
• Better control over active sessions
• Requires server-side storage
• Challenging to scale horizontally
• Less suitable for distributed systems
• CSRF vulnerability (requires protection)
• Not ideal for mobile APIs
• Traditional web applications
• E-commerce platforms
• Banking applications
• Admin panels
• Examples: WordPress, Magento, traditional PHP applications
OAuth 2.0
• Delegated authorization
• No password sharing
• Granular permission scopes
• Revocable access tokens
• Industry standard
• Refresh token mechanism
• Complex to implement correctly
• Multiple flows to understand
• Requires understanding of various grant types
• Can be overkill for simple apps
• Third-party API integrations
• Social login (Login with Google/Facebook)
• Mobile app authentication
• Service-to-service authorization
• Examples: GitHub API, Google Drive integration, Twitter API, Slack apps
Basic Authentication
• Simple to implement
• Widely supported
Stateless
• Good for testing/development
• Credentials sent with every request
• No built-in expiration
• No encryption (must use HTTPS)• Poor user experience
• Vulnerable to credential exposure
• Development and testing
• Internal tools
• Simple APIs with minimal security needs
• Legacy system integration
• Examples: Simple REST APIs, IoT devices, development environments
API Keys
• Very simple to implement
• Good for service-to-service auth• Easy to revoke/rotate
• Stateless
• Static (no expiration by default)
• No built-in user context
• All-or-nothing access
• Must be stored securely
• Public API access
• Service-to-service communication
• Monitoring services
• Third-party integrations
• Examples: Google Maps API, Stripe API, SendGrid, OpenAI API
SAML (Security Assertion Markup Language)
• Rich security assertions
• Enterprise-grade features
• Proven in large organizations
• Detailed user attributes
• Works well with SSO
• XML-based (verbose)
• Complex to implement
• Higher overhead
• Steep learning curve
• Primarily for web browsers
• Enterprise SSO
• B2B applications
• Corporate intranets
• Government systems
• Examples: Salesforce Enterprise, Microsoft 365, Workday, ServiceNow
OpenID Connect (OIDC)
• Standardized authentication
• Built on OAuth 2.0
• Can use JWT tokens
• Profile information included
• Modern and widely adopted
• More complex than basic JWT
• Requires understanding of OAuth 2.0
• Multiple endpoints to manage
• Modern web applications
• Mobile applications
• Multi-tenant SaaS platforms
• Consumer-facing apps with social login
• Examples: Auth0, Okta, Google Identity Platform, AWS Cognito
Choosing the Right Authentication Method
When selecting an authentication strategy, consider the following factors:
For Single Page Applications (SPAs) and Mobile Apps: JWT or OAuth 2.0 with OIDC are typically the best choices due to their stateless nature and flexibility.
For Traditional Web Applications: Session-based authentication remains a solid choice, especially when server-side rendering is involved and immediate session invalidation is important.
For Enterprise Applications: SAML or OpenID Connect are preferred, particularly when SSO capabilities are required across multiple services.
For Public APIs: API Keys combined with OAuth 2.0 provide a good balance of simplicity and security.
For Microservices: JWT tokens work well due to their stateless nature and ability to carry user context across service boundaries.
Authorizing with JSON Web Token
For our authorization purposes, we'll use an NPM popular library: jsonwebtoken. More information at https://www.npmjs.com/package/jsonwebtoken
The library has two main functions:
Generate a token,
.sign()
. This receives multiple arguments:User identification information - which can be later decoded
A private key to generate the hash tokens
Options such as expiration dates
Decode an access token,
.verify()
. This receives the following arguments:The access token
The private key to decode it
A callback function that returns an
error
object, in case the validity of the token fails, and thedecoded
object
Basic JWT Auth Example
const express = require('express');
const jwt = require('jsonwebtoken'); // npm install jsonwebtoken
const cors = require('cors');
const app = express();
app.use(cors());
app.use(express.json());
const secret = 'serverKeptSecret'; // In production, use environment variables!
// AUTHENTICATION ENDPOINT
app.post('/login', (req, res) => {
const { email, password } = req.body;
// Validate credentials (in production, check against database)
// This is a simplified example
if (email === 'user@example.com' && password === 'password123') {
// Create token with user identification data
const tokenEncodedData = {
email: email,
role: 'user'
};
// Generate token with 1-hour expiration
const token = jwt.sign(tokenEncodedData, secret, { expiresIn: 3600 });
res.json({
success: true,
token: token,
message: 'Authentication successful'
});
} else {
res.status(401).json({
success: false,
message: 'Invalid credentials'
});
}
});
// MIDDLEWARE - Verify token
function verifyToken(req, res, next) {
const bearerHeader = req.headers['authorization'];
if (typeof bearerHeader !== 'undefined') {
const bearer = bearerHeader.split(' ');
const bearerToken = bearer[1];
req.token = bearerToken;
next();
} else {
res.sendStatus(401);
}
}
// PROTECTED ROUTE
app.get('/private', verifyToken, (req, res) => {
jwt.verify(req.token, secret, (err, decoded) => {
if (err) {
if (err.name === 'TokenExpiredError') {
res.status(401).json({
message: 'Your token has expired. Please re-authenticate'
});
} else {
res.status(403).json({
message: 'You are NOT authorized to access this resource'
});
}
} else {
// Access granted - we can use decoded data
console.log('Authenticated user:', decoded.email);
res.json({
message: 'Well kept secret',
user: decoded.email
});
}
});
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Other Authentication Methods
Session-based Authentication
Session-based authentication maintains server-side state for authenticated users. The server creates a session upon successful login, stores it (in memory, database, or Redis), and returns a session ID as a cookie. The client automatically includes this cookie in subsequent requests.
Key characteristics: Server maintains state, immediate session invalidation possible, requires shared storage for distributed systems, vulnerable to CSRF (requires protection), ideal for traditional server-rendered applications.
OAuth 2.0
OAuth 2.0 is an authorization framework enabling applications to access user data on third-party services without exposing credentials. Users authorize applications through the service that hosts their account.
Common flows: Authorization Code (most secure, for web/mobile apps), Client Credentials (machine-to-machine), Implicit (deprecated).
Flow: Application redirects to authorization server → User authenticates and grants permission → Authorization code returned → Exchanged for access token → Token used to access resources.
Use cases: Social login ("Login with Google/Facebook"), third-party API integrations, delegated authorization, microservices.
API Keys
API keys are simple static tokens used to authenticate API requests, typically included in headers (X-API-Key
) or query parameters. They provide single-purpose authentication suitable for rate limiting and tracking.
Best practices: Never expose in client-side code, rotate regularly, use different keys per environment, implement rate limiting, restrict by IP/domain.
Limitations: No user context, typically all-or-nothing access, must be manually revoked if compromised.
SAML (Security Assertion Markup Language)
SAML is an XML-based framework for exchanging authentication and authorization data, predominantly used for enterprise Single Sign-On. An Identity Provider (IdP) authenticates users and sends digitally signed XML assertions to Service Providers (applications).
Flow: User accesses app → Redirected to IdP → Authenticates → IdP sends signed assertion → App validates and grants access.
Best for: Enterprise environments, centralized identity management, cross-domain SSO, complex compliance requirements, B2B applications.
OpenID Connect (OIDC)
OpenID Connect extends OAuth 2.0 with standardized authentication, adding identity verification capabilities. It returns ID tokens (JWTs) containing user identity information alongside OAuth access tokens.
Key features: Standardized authentication protocol, structured user info in ID tokens, built-in session management, standardized discovery mechanisms.
Use cases: Modern web/mobile applications, multi-tenant SaaS platforms, consumer apps with social login, microservices requiring user context.
Basic Authentication
Basic Authentication sends base64-encoded credentials (username:password
) in the Authorization header with each request. It's the simplest HTTP authentication scheme but offers minimal security.
Format: Authorization: Basic [base64-encoded-credentials]
Limitations: Credentials sent with every request, base64 is encoding not encryption, no expiration or logout, requires HTTPS, no replay attack protection.
Appropriate for: Development/testing, simple internal APIs, legacy systems, IoT devices with limited resources.
Single Sign-On (SSO)
SSO (Single Sign-On) enables one-time login across multiple applications using a central Identity Provider (IdP) like Okta, Azure AD, or Google Workspace.
Basic flow:
User visits App A → redirects to IdP
User logs into IdP once
IdP sends signed token back to App A
When user visits App B, IdP sees existing session → auto-login
This works cross-domain through:
SAML or OpenID Connect protocols
Browser redirects and POST bindings
Digitally signed tokens (XML/JWT)
IdP session cookies
Key benefits:
One login for multiple applications
Centralized user management
Unified security policies
Easy access revocation
Comprehensive audit logging
Security Best Practices
Essential security practices regardless of authentication method:
Transport & Storage: Always use HTTPS, use secure password hashing (bcrypt, Argon2), never store passwords in plain text.
Attack Prevention: Implement rate limiting, use CAPTCHA for repeated failures, monitor suspicious patterns.
Token Management: Set appropriate expiration times, implement refresh token rotation, invalidate tokens on logout.
Cookie Security: Use HttpOnly and Secure flags, implement proper CORS policies.
Maintenance: Log authentication attempts, keep dependencies updated, conduct regular security audits.
Conclusion
Selecting the appropriate authentication strategy depends on your application's architecture, security requirements, and user experience goals. JWT excels in stateless distributed systems, sessions work well for traditional web applications, OAuth 2.0/OIDC handle third-party integrations, and SAML serves enterprise SSO needs. Understanding these options enables informed decisions balancing security, scalability, and usability.
Last updated
Was this helpful?