Post

Implementing Mutual TLS Authentication

A step-by-step guide to implementing mutual TLS (mTLS) authentication in FastAPI using OpenSSL and Uvicorn.

Implementing Mutual TLS Authentication

Mutual TLS (mTLS) authentication is like a secret handshake between your client and server—both parties show their secret badges (certificates) before they start chatting. This mechanism is widely used in secure API communications, microservices, and zero-trust architectures.


How Mutual TLS Works

  1. Client Hello
    The client initiates a connection with a TLS handshake.
  2. Server Certificate
    The server presents its certificate to prove its identity.
  3. Client Certificate Request
    The server asks, “Who are you?” by requesting a certificate from the client.
  4. Client Certificate Verification
    The client provides its certificate, and the server verifies it—think of it as checking the secret handshake.
  5. Secure Communication
    Once both sides are satisfied, encrypted communication begins.

mTLS Handshake Diagram

Below is a Mermaid diagram that visually represents the mTLS handshake process:

sequenceDiagram
    participant C as Client
    participant S as Server
    participant CA as Certificate Authority

    C->>S: Client Hello
    S->>C: Server Certificate (Issued by CA)
    S->>C: Request Client Certificate
    C->>S: Client Certificate (Issued by CA)
    S->>CA: Verify Client Certificate
    Note over C,S: Mutual TLS Authentication Successful
    C->>S: Encrypted Request
    S->>C: Encrypted Response

Generating Certificates with OpenSSL

Before you implement the mTLS connection in your application, you need to generate certificates. Here’s how to create a Certificate Authority (CA) and then issue certificates for the server and client.

1. Generate CA Certificate

1
2
openssl req -x509 -newkey rsa:4096 -days 365 -nodes \
  -keyout ca.key -out ca.crt -subj "/CN=MyCA"

2. Generate Server Certificate

1
2
openssl req -newkey rsa:4096 -nodes -keyout server.key -out server.csr -subj "/CN=server"
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365

3. Generate Client Certificate

1
2
openssl req -newkey rsa:4096 -nodes -keyout client.key -out client.csr -subj "/CN=client"
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365

Implementing mTLS in Python with FastAPI and Uvicorn

Below is an example of a FastAPI application configured for mTLS using Uvicorn and Python’s ssl module.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from fastapi import FastAPI
import ssl

app = FastAPI()

@app.get("/")
async def secure_endpoint():
    return {"message": "Hello, you have successfully authenticated using mTLS!"}

if __name__ == "__main__":
    # Create an SSL context that requires client certificates.
    ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    ssl_context.load_cert_chain(certfile="server.crt", keyfile="server.key")
    ssl_context.load_verify_locations(cafile="ca.crt")
    ssl_context.verify_mode = ssl.CERT_REQUIRED  # Enforce client authentication

    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000, ssl_context=ssl_context)

Testing the mTLS Connection

After setting up your server, test the mTLS configuration using curl.

Successful Authentication (With Client Certificate)

1
curl --cert client.crt --key client.key --cacert ca.crt https://localhost:8000/

Failed Authentication (Without Client Certificate)

1
curl --cacert ca.crt https://localhost:8000/

Skipping the client certificate should cause the connection to be rejected—just like trying to enter an exclusive club without the proper credentials!


Conclusion

  • Mutual TLS ensures both the client and the server prove their identities—a true two-way authentication.
  • FastAPI + Uvicorn: This combo easily supports mTLS using Python’s ssl module.
  • OpenSSL: The go-to tool for generating the necessary certificates.

With this setup, every connection is double-checked, making your communications as secure as a VIP event. Happy coding and secure connecting!

This post is licensed under CC BY 4.0 by the author.