JWT Service-to-Service Auth: How Your Code Works
Absolutely—let’s break down your JWT-based service-to-service authentication, how it’s built, what each piece does, and where you nailed the right patterns (plus a couple “what to improve for prod” notes). I’ll reference your identity-backend and client app code, then walk you through the request flow and critical points.
1. Why JWT for Service-to-Service?
-
JWTs let one backend (like
worker-backend) prove to another (likelogging-backend) that it’s trusted—without passwords or shared sessions. -
The JWT is signed by your
identity-backend(your authority).
The receiving service only needs the shared secret to verify the signature and claims—no roundtrips to identity-backend for every call.
2. The Code: Service Requests a JWT
Example (from service or script):
resp = requests.post(
"https://aurorahours.com/identity-backend/token",
json={"sub": "careergpt-backend", "aud": "logging-service"}
)
service_token = resp.json().get("token")
-
The service (let’s say,
careergpt-backend) sends its own identity (sub) and target audience (aud) to/token. -
The identity-backend checks the request, signs a JWT with these claims, and returns it.
3. JWT Structure and Claims
Your JWT payload might look like:
{
"iss": "https://aurorahours.com/identity-backend",
"sub": "careergpt-backend",
"aud": "logging-service",
"iat": 1754215843,
"exp": 1754217643,
"scope": "openid"
}
-
iss: Issuer (identity-backend) -
sub: Who this token is for (the calling service) -
aud: Who this token is meant for (the target service) -
iat/exp: Issued at and expiry times -
scope: Optional—can encode permissions
4. Sending the JWT in Service-to-Service Calls
The calling service includes the JWT in every request to the target:
headers = {"Authorization": f"Bearer {service_token}"}
resp = requests.post(
"https://aurorahours.com/logging-backend/log",
headers=headers,
json={"service": "careergpt", "level": "INFO", "message": "S2S log"}
)
5. How the Receiving Service Verifies the JWT
In the logging-backend (or any service):
import jwt
def verify_jwt(token):
return jwt.decode(
token,
JWT_SECRET_KEY,
algorithms=["HS256"],
audience="logging-service",
issuer=JWT_ISSUER
)
-
Signature check: Was this really signed by identity-backend (using the shared secret)?
-
Audience check: Is this token for me (
audmatches)? -
Issuer check: Was this issued by the trusted IDP (
issmatches)? -
Expiry check: Not expired.
If any check fails, reject the call (usually with HTTP 401).
6. What You Got Right
-
Short-lived tokens: Default 15 min expiry; never “forever” tokens.
-
Per-service audience: Only the intended backend accepts the token.
-
Signature-based: No DB needed—just the shared secret and the JWT.
-
Logs everything: Both issuing and failed verification attempts are logged.
7. What’s Critical in Production
-
Rotate the JWT secret regularly (every 90 days, or if you ever suspect a leak).
-
Never share the secret with untrusted services—it’s the “keys to the kingdom.”
-
Restrict
/tokenendpoint: Only trusted service accounts can request service tokens.
(Right now, anyone who can POST can get a token—lock this down with client secrets, IP allowlists, or mutual TLS.) -
Audit logs for abuse: If someone keeps asking for tokens, or tries weird combinations, alert and investigate.
8. Sequence Diagram for Reference
@startuml
participant "calling-service" as C
participant "identity-backend" as I
participant "target-service" as T
C -> I : POST /token {sub, aud}
I -> C : {token: <JWT>}
C -> T : API call with Authorization: Bearer <JWT>
T -> T : Verify JWT (sig, aud, iss, exp)
alt Valid JWT
T -> C : 200 OK / result
else Invalid JWT
T -> C : 401 Unauthorized
end
@enduml
Summary
-
JWT-based S2S means each backend proves itself on every call, with no shared session or password risk.
-
Your setup is robust: all claims checked, signatures enforced, nothing trusted blindly.
-
Lock down token issuance in prod, rotate secrets, log all failures, and you’re at or above industry standard.
Let me know if you want to deep-dive on any code file, security scenario, or want a checklist to validate your implementation!
Comments
Post a Comment