Why This Isn’t Secure
Why This Isn’t Secure
-
Single secret for everything: If one service or dev leaks the key, all access is compromised.
-
No user or service identity: You can’t differentiate which service made the request (no audit trail).
-
No expiration: Keys never expire unless you rotate manually.
-
Bearer token misuse: Bearer JWTs should be signed tokens carrying claims, not static secrets.
What Should Happen Instead
1. Identity Service Issues JWTs
-
Your identity-backend becomes the trust anchor.
-
It issues signed JWTs with claims like:
{ "iss": "identity-backend", "aud": "logging-service", "sub": "careergpt-backend", "exp": 1735564800 } -
JWT is signed with private key (or shared HMAC for MVP).
2. Each Microservice Validates JWT
-
log-servicechecks:-
Signature is valid.
-
Audience =
logging-service. -
Issuer =
identity-backend. -
Expiry not passed.
-
-
No need to share
LOG_SERVICE_KEYbetween services.
3. Rotate & Revoke
-
You can rotate signing keys without redeploying every service.
-
You can revoke tokens for one service/user without affecting others.
4. Service-to-Service Auth Model
-
For internal service calls (careergpt → logging):
-
Service authenticates with identity-backend once.
-
Gets a short-lived JWT (e.g., 15 min).
-
Sends that JWT in
Authorization: Bearer.
-
-
For user-facing requests:
-
User logs in, identity-backend issues JWT.
-
Frontend uses that JWT to call careergpt-backend (and careergpt calls logging).
-
Where Your Current Setup Fits
-
Right now,
LOG_SERVICE_KEYis a stopgap: quick way to lock down endpoints. -
But in production, it should evolve into:
-
JWT validation (HMAC or RSA).
-
No hardcoded shared secrets between services.
-
Short-lived tokens issued by identity service.
-
Want to Transition?
We can design this incrementally:
-
Keep current
LOG_SERVICE_KEYfor MVP (service-to-service lock). -
Add JWT validation to logging service.
-
Modify identity service to issue JWTs.
-
Update careergpt-backend to fetch JWTs and pass them.
Do you want me to redesign the logging service now to validate real JWTs (future-proof)?
Or keep static key for MVP and show next-step plan to migrate to proper JWT-based service authentication?
Perfect timing — now that the logging microservice MVP is stable, we can spin up the identity-backend as the next microservice. I’ll outline the setup for cPanel and provide MVP code that issues JWTs for other microservices (like careergpt-backend and logging-service) to validate.
Phase 1: Setup for cPanel
1. Create identity-backend directory
-
Inside your repo or as a separate service:
identity-backend/
├── app.py
├── passenger_wsgi.py
├── requirements.txt
├── config.py
├── models.py (optional for future user/service storage)
└── .gitignore
2. Environment variables in cPanel
Add these in the Python App Environment Variables:
JWT_SECRET_KEY = <generate-a-strong-random-string>
JWT_ISSUER = identity-backend
JWT_EXPIRATION_MINUTES = 15
(Later we’ll add support for RSA public/private keys, but HMAC is simpler for MVP.)
3. Application startup file
Set to:
passenger_wsgi.py
Contents:
from app import app as application
Phase 2: MVP Code for Identity Backend
config.py
import os
from dotenv import load_dotenv
# Load .env if available (local dev)
load_dotenv()
JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY", "dev-secret") # HMAC key for signing
JWT_ISSUER = os.getenv("JWT_ISSUER", "identity-backend")
JWT_EXPIRATION_MINUTES = int(os.getenv("JWT_EXPIRATION_MINUTES", 15))
app.py
from flask import Flask, request, jsonify
import jwt
import datetime
from config import JWT_SECRET_KEY, JWT_ISSUER, JWT_EXPIRATION_MINUTES
app = Flask(__name__)
# Generate a JWT for a service (e.g., logging-service, careergpt-backend)
@app.route("/token", methods=["POST"])
def generate_token():
"""
Request body:
{
"sub": "careergpt-backend",
"aud": "logging-service"
}
"""
data = request.get_json()
if not data or "sub" not in data or "aud" not in data:
return jsonify({"error": "Missing required claims (sub, aud)"}), 400
now = datetime.datetime.utcnow()
payload = {
"iss": JWT_ISSUER,
"sub": data["sub"],
"aud": data["aud"],
"iat": now,
"exp": now + datetime.timedelta(minutes=JWT_EXPIRATION_MINUTES)
}
token = jwt.encode(payload, JWT_SECRET_KEY, algorithm="HS256")
return jsonify({"token": token})
# Verify JWT (optional debug endpoint)
@app.route("/verify", methods=["POST"])
def verify_token():
data = request.get_json()
token = data.get("token")
try:
decoded = jwt.decode(token, JWT_SECRET_KEY, algorithms=["HS256"], audience=data.get("aud"))
return jsonify({"valid": True, "claims": decoded})
except jwt.ExpiredSignatureError:
return jsonify({"valid": False, "error": "Token expired"}), 401
except jwt.InvalidTokenError as e:
return jsonify({"valid": False, "error": str(e)}), 401
if __name__ == "__main__":
app.run(port=5002)
requirements.txt
Flask==2.3.2
PyJWT==2.8.0
python-dotenv==1.0.0
Phase 3: How It Works
-
Generate token for service
curl -X POST https://aurorahours.com/identity/token \
-H "Content-Type: application/json" \
-d '{"sub":"careergpt-backend","aud":"logging-service"}'
-
Use token in logging-service
curl https://aurorahours.com/logging/logs \
-H "Authorization: Bearer <JWT_FROM_IDENTITY>"
-
logging-service validates token (next phase: replace
LOG_SERVICE_KEYcheck with JWT validation)
Next Steps
-
Deploy this MVP to cPanel (same process as logging-service).
-
Test issuing and verifying tokens.
-
Update logging-service to accept JWT from identity-backend and validate claims (issuer, audience, expiry).
-
Remove static
LOG_SERVICE_KEYonce JWT works end-to-end.
Do you want me to write the JWT validation code for logging-service now (so it’s ready to accept tokens immediately)?
Or deploy identity-backend first, confirm it works on cPanel, and then integrate logging-service?
Comments
Post a Comment