πAppendix C
JWT Authentication in a Microservice Architecture
Introduction
In modern applications, especially those built on a microservices architecture, services need to communicate with each other securely. A common challenge is handling user authentication and authorization across these distributed services. Sharing a single secret key (as used with the HS256 algorithm) among all services is a security risk; if one service is compromised, the entire system's secret is exposed.
A more secure and scalable solution is to use an asymmetric key pair (RS256). In this pattern, a dedicated Authentication Service signs JWTs with a private key, while multiple Resource Services verify those tokens using a corresponding public key.
This appendix provides a step-by-step guide to implementing this pattern using two FastAPI applications.
auth_service: The central authority that validates user credentials and issues JWTs. It is the only service that holds the private key.course_service: A resource service that protects its endpoints and provides data only to requests with a valid JWT. It only needs the public key to verify tokens.
Core Concept: Asymmetric Keys (RS256)
Unlike symmetric algorithms (like HS256) that use one secret key for both signing and verifying, asymmetric algorithms use a pair of keys:
Private Key (.pem) π: Kept secret and known only to the
auth_service. It is used to sign (create) the JWT. Think of it as the unique, personal signature of the issuer.Public Key (.pub) π: Can be shared freely with any number of resource services. It is used to verify the signature of a JWT. Anyone with the public key can confirm that the token was signed by the holder of the private key, but they cannot create new valid tokens themselves.
This separation is the key to the pattern's security and scalability.
Implementation Walkthrough
Step 1: Generate the RSA Key Pair
First, you need to generate the private and public keys. You can do this using the openssl command-line tool.
Generate a 2048-bit RSA Private Key:
Extract the Public Key from the Private Key:
You will now have two files in your directory: private_key.pem and public_key.pem.
Step 2: Build the Authentication Service
Create a file named auth_service.py. This service will issue tokens signed with the private key.
Step 3: Build the Resource Service
Create a second file named course_service.py. This service will use the public key to validate tokens and protect its data.
Step 4: Run and Test the Services
Open two separate terminal windows in your project directory.
1/ Start the Authentication Service on port 8081:
2/ Start the Course Service on port 8082:
3/ Test the Flow:
Navigate to the
auth_servicedocs at http://127.0.0.1:8081/docs.Use the
/tokenendpoint withusername: "student1"andpassword: "password123"to get an access token.Copy the
access_tokenstring.Navigate to the
course_servicedocs at http://127.0.0.1:8082/docs.Click the "Authorize" button, paste the token into the value field, and authorize.
Now, execute the
/coursesendpoint. You should successfully receive the list of courses.
Architectural Benefits of This Pattern
No Shared Secrets: The highly sensitive private key is isolated within the
auth_service. Resource services don't need it, minimizing the attack surface.Decentralized Verification: Any number of microservices can be given the public key to verify tokens independently. This allows them to protect their endpoints without needing to call the
auth_servicefor every request, which is highly efficient and scalable.Improved Security Posture: If a
course_serviceinstance is compromised, attackers cannot issue new, valid tokens because they do not have the private key. The scope of the breach is limited.
Last updated