API and API Designs: API Authentication

In this episode, we will discuss API Authentication, we will look at methods such as Basic Auth, Token Based Auth, JWT, Session Auth, OAuth 2.0, etc.

In partnership with

Hello “👋

Welcome to another week, another opportunity to become a Great Backend Engineer.

Today’s issue is brought to you by Masteringbackend → A great resource for backend engineers. We offer next-level backend engineering training and exclusive resources.

Learn how to make AI work for you.

The Rundown is the world’s largest AI newsletter, with over 700,000+ early adopters staying up-to-date with the latest AI news, and learning how to apply it in their work in just a 5 minute read per day.

  1. Their expert team spends all day researching and talking with industry experts.

  2. They send updates on the latest AI news and how to apply it in 5 minutes a day.

  3. You learn how to become 2x more productive by leveraging AI.

Now, back to the business of today.

In my previous series, I explored everything you need to know and learn about API fundamentals.

Today, we will discuss API Authentication, we will look at methods such as Basic Auth, Token Based Auth, JWT, Session Auth, OAuth 2.0, etc.

This comes from my Backend Engineering Hub under the API and API Design section. However, I’m only transferring the knowledge here and breaking it down in this series one topic at a time.

What is API Authentication?

APIs are a powerful way of communicating with systems and transferring information between two or more systems. However, this communication needs to be secured.

Therefore, to ensure secure communication, it’s essential to authenticate the parties involved in the API communication.

That is where API Authentication comes in. There are many ways to authenticate an API communication when designing an API.

We are going to explore a few listed below:

  • Basic Auth,

  • Token Based Auth,

  • JWT,

  • Session Auth,

  • OAuth 2.0

Understanding these different methods and their best use cases is fundamental to designing secure and effective APIs.

Basic Auth

Basic Authentication, or Basic Auth, is one of the simplest methods to secure API endpoints. It involves sending a user's credentials (username and password) in the HTTP header of each API request. While it is easy to implement and widely supported, it has inherent security limitations that require careful consideration.

How Basic Authentication Works

  1. Client Sends Credentials: The client encodes the username and password in Base64 format and includes them in the Authorization header of the HTTP request.

  2. Server Validates: The API server decodes the credentials, validates them against a data source (e.g., a database), and determines if the client has access to the requested resource.

  3. Response:

    • If credentials are valid, the server grants access and responds with the requested resource.

    • If invalid, the server denies access and returns an appropriate HTTP status code (e.g., 401 Unauthorized).

Implementation

const express = require('express');
const app = express();

// Middleware for Basic Auth
app.use((req, res, next) => {
    const authHeader = req.headers['authorization'];
    if (!authHeader) {
        return res.status(401).json({ message: 'Authorization header missing' });
    }

    // Decode Base64 encoded credentials
    const base64Credentials = authHeader.split(' ')[1];
    const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
    const [username, password] = credentials.split(':');

    // Validate credentials (replace with actual validation logic)
    if (username === 'apiUser' && password === 'securePass') {
        next(); // Proceed to the protected route
    } else {
        res.status(401).json({ message: 'Invalid credentials' });
    }
});

// Protected route
app.get('/resource', (req, res) => {
    res.json({ message: 'Access granted to protected resource' });
});

// Start the server
app.listen(3000, () => console.log('Server running on port 3000'));

Basic Authentication is a straightforward and universally supported method for API authentication, making it suitable for simple or internal applications. However, its security limitations necessitate careful usage, particularly in production environments. When using Basic Auth, always employ HTTPS and consider augmenting it with other security practices to mitigate risks.

Token Based Auth

Token-based authentication is a widely adopted method in API design, ensuring secure and scalable access to resources. This approach relies on issuing a unique token to the client upon successful authentication, which is then used in subsequent API requests as proof of identity.

How Token-Based Authentication Works

  1. Client Authenticates: The client sends a request to the server with valid credentials (e.g., username and password).

  2. Token Issuance: Upon successful authentication, the server generates a token (e.g., JWT or opaque token) and sends it to the client.

  3. Token Storage: The client securely stores the token, typically in local storage, session storage, or a cookie.

  4. Token Inclusion in Requests: For every API request, the client includes the token in the Authorization header.

  5. Server Validates Token: The server decodes and verifies the token. If valid, the request is processed; otherwise, access is denied.

  6. Access Granted or Denied: Valid tokens grant access to resources, while expired or tampered tokens result in an error (e.g., 401 Unauthorized).

Implementation

const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();

const SECRET_KEY = 'your_secret_key';

// Middleware to validate token
function authenticateToken(req, res, next) {
    const authHeader = req.headers['authorization'];
    const token = authHeader && authHeader.split(' ')[1];

    if (!token) return res.status(401).json({ message: 'Token missing' });

    jwt.verify(token, SECRET_KEY, (err, user) => {
        if (err) return res.status(403).json({ message: 'Invalid token' });
        req.user = user;
        next();
    });
}

// Login route
app.post('/login', (req, res) => {
    const { username, password } = req.body;

    // Replace with actual user authentication
    if (username === 'user' && password === 'pass') {
        const token = jwt.sign({ username }, SECRET_KEY, { expiresIn: '1h' });
        res.json({ token });
    } else {
        res.status(401).json({ message: 'Invalid credentials' });
    }
});

// Protected route
app.get('/protected', authenticateToken, (req, res) => {
    res.json({ message: 'Access granted to protected resource', user: req.user });
});

app.listen(3000, () => console.log('Server running on port 3000'));

JWT

JSON Web Tokens (JWT) is a widely used mechanism for securing API communication. They are compact, self-contained tokens used to verify the identity of users and securely transmit information between parties. JWTs are popular for authentication, authorization, and secure data exchange in modern applications, particularly in distributed systems and microservices architectures.

A JWT is a Base64-encoded string that consists of three parts:

  1. Header: Metadata about the token, including the type (JWT) and the algorithm used for signing.

  2. Payload: The claims or data being transmitted (e.g., user ID, roles).

  3. Signature: A cryptographic signature generated using the header, payload, and a secret or private key.

How JWT Authentication Works

  1. Login: User submits credentials (e.g., username and password).

  2. Token Issuance: The server validates credentials and generates a JWT containing user information and expiration time.

  3. Client Stores Token: The client stores the JWT securely (e.g., in local storage, session storage, or HTTP-only cookies).

  4. Authenticated Requests: The client includes the JWT in the Authorization header for subsequent API requests:

  5. Server Validates Token: The server verifies the token’s signature, checks claims like expiration, and processes the request if valid.

Implementation

Token Generation (Node.js with jsonwebtoken)

const jwt = require('jsonwebtoken');

const SECRET_KEY = 'your_secret_key';

// Generate a token
function generateToken(user) {
    const payload = {
        userId: user.id,
        role: user.role,
    };
    return jwt.sign(payload, SECRET_KEY, { expiresIn: '1h' });
}

// Example usage
const user = { id: '1234', role: 'admin' };
const token = generateToken(user);
console.log('Generated Token:', token);

Token Validation Middleware

const express = require('express');
const jwt = require('jsonwebtoken');

const app = express();
const SECRET_KEY = 'your_secret_key';

// Middleware for token validation
function authenticateToken(req, res, next) {
    const authHeader = req.headers['authorization'];
    const token = authHeader && authHeader.split(' ')[1];

    if (!token) return res.status(401).json({ message: 'Token missing' });

    jwt.verify(token, SECRET_KEY, (err, user) => {
        if (err) return res.status(403).json({ message: 'Invalid token' });
        req.user = user;
        next();
    });
}

// Protected route
app.get('/protected', authenticateToken, (req, res) => {
    res.json({ message: 'Access granted', user: req.user });
});

app.listen(3000, () => console.log('Server running on port 3000'));

JWTs are a powerful tool for modern authentication and authorization, offering scalability, flexibility, and security. However, they require careful implementation to avoid common pitfalls. By adhering to best practices, developers can leverage JWTs effectively in their applications, providing secure and efficient user authentication.

Session Based Auth

Session-based authentication is a well-established method for managing user authentication in web and API design. This approach involves maintaining a session on the server side that is associated with a unique identifier (Session ID).

When a user logs in, the server creates a session and assigns it a Session ID, which is stored on the client side, typically in a browser cookie. For every subsequent request, the client includes this Session ID, allowing the server to verify and authenticate the user.

How Session-Based Authentication Works

  1. User Login: The client submits login credentials (e.g., username and password) to the server.

  2. Session Creation: Upon successful authentication, the server generates a session and associates it with a unique Session ID. This Session ID is stored in the server’s session store.

  3. Session ID Storage: The server sends the Session ID to the client, which stores it in a cookie.

  4. Authenticated Requests: For subsequent API requests, the client includes the Session ID in the HTTP headers (via the cookie).

  5. Session Validation: The server checks the Session ID against its session store. If the Session ID is valid, the server processes the request.

  6. Session Expiry or Logout: When the user logs out or the session expires, the server removes the session from its store, invalidating the Session ID.

Implementation

const express = require('express');
const session = require('express-session');

const app = express();

// Configure session middleware
app.use(session({
    secret: 'your_secret_key', // Use a secure key
    resave: false,             // Avoid resaving unmodified sessions
    saveUninitialized: true,   // Save new sessions even if they are empty
    cookie: {
        httpOnly: true,        // Mitigate XSS
        secure: false,         // Set to true in production with HTTPS
        maxAge: 60000          // Session expiration time in milliseconds
    }
}));

// Example login route
app.post('/login', (req, res) => {
    // Simulate user authentication
    const user = { id: 1, username: 'admin' };
    
    // Save user information in session
    req.session.user = user;
    res.json({ message: 'Login successful' });
});

// Protected route
app.get('/dashboard', (req, res) => {
    if (!req.session.user) {
        return res.status(401).json({ message: 'Unauthorized' });
    }
    res.json({ message: `Welcome, ${req.session.user.username}` });
});

// Logout route
app.post('/logout', (req, res) => {
    req.session.destroy(err => {
        if (err) {
            return res.status(500).json({ message: 'Logout failed' });
        }
        res.clearCookie('connect.sid'); // Clear session cookie
        res.json({ message: 'Logout successful' });
    });
});

// Start server
app.listen(3000, () => console.log('Server running on port 3000'));

OAuth 2.0

OAuth 2.0 is a widely adopted authorization framework that facilitates secure and delegated access to user resources without sharing credentials. Designed to enhance both security and usability, it enables third-party applications to access user accounts hosted by resource servers like Facebook, Google, GitHub, or custom APIs.

OAuth 2.0 shifts the responsibility of user authentication from the client application to an authorization server, improving both user privacy and security. This article explores the core principles, roles, workflows, and best practices of OAuth 2.0 in API design.

I will send a detailed article on OAuth 2.0.

That will be all for today. I like to keep this newsletter short.

Did you learn any new things from this newsletter this week? Please reply to this email and let me know. Feedback like this encourages me to keep going.

See you on Next Week.

Remember to start learning backend engineering from our courses:

Top 5 Remote Backend Jobs this week

Here are the top 5 Backend Jobs you can apply to now.

👨‍💻 SAP Fioneer
✍️ Backend Engineer
📍Remote
💰 Click on Apply for salary details
Click here to Apply for this role.

👨‍💻 AArete
✍️ Backend Engineer
📍Remote, Worldwide
💰 Click on Apply for salary details
Click here to Apply for this role.

👨‍💻 FREE NOW
✍️ Backend Engineer (m/f/d) - Barcelona
📍Remote, Worldwide
💰 Click on Apply for salary details
Click here to Apply for this role.

👨‍💻 FREE NOW
✍️ Backend Engineer (m/f/d) - Madrid
📍Remote
💰 Click on Apply for salary details
Click here to Apply for this role.

Want more Remote Backend Jobs? Visit GetBackendJobs.com

Backend Engineering Resources

Whenever you're ready

There are 4 ways I can help you become a great backend engineer:

1. The MB Platform: Join 1000+ backend engineers learning backend engineering on the MB platform. Build real-world backend projects, track your learnings and set schedules, learn from expert-vetted courses and roadmaps, and solve backend engineering tasks, exercises, and challenges.

2. The MB Academy:​ The “MB Academy” is a 6-month intensive Advanced Backend Engineering BootCamp to produce great backend engineers.

3. MB Video-Based Courses: Join 1000+ backend engineers who learn from our meticulously crafted courses designed to empower you with the knowledge and skills you need to excel in backend development.

4. GetBackendJobs: Access 1000+ tailored backend engineering jobs, manage and track all your job applications, create a job streak, and never miss applying. Lastly, you can hire backend engineers anywhere in the world.

LAST WORD 👋 

How am I doing?

I love hearing from readers, and I'm always looking for feedback. How am I doing with The Backend Weekly? Is there anything you'd like to see more or less of? Which aspects of the newsletter do you enjoy the most?

Hit reply and say hello - I'd love to hear from you!

Stay awesome,
Solomon

I moved my newsletter from Substack to Beehiiv, and it's been an amazing journey. Start yours here.

Reply

or to participate.