Next mvp - Logging has Login, using identity-backend
Great, I have now fully consumed both microservices.
Next, I'll outline how to implement robust, identity-backend-controlled authentication and login for your /logs endpoint.
Context Recap
-
identity-backend:
-
Issues/validates JWTs, but currently only supports service tokens (not user sessions/logins).
-
No UI, but could easily serve login pages or handle user credentials.
-
-
-
Exposes
/logs(and related endpoints) protected by JWT (validated locally using the shared secret, audience, and issuer). -
No UI, currently expects Authorization header in every request.
-
No notion of "users"—only services with JWTs.
-
Your Goal
-
Make
/logsa secure log viewer accessible only to authenticated users. -
Delegate all authentication and login logic to identity-backend.
-
Enable identity-backend to serve a login page for any microservice, not just logging-backend.
1. Proposed Authentication Flow
A. Browser/User visits /logging-backend/logs:
-
If JWT cookie is missing or invalid, redirect to
/identity-backend/login?redirect_url=https://aurorahours.com/logging-backend/logs -
identity-backend serves a login page, authenticates user, issues JWT as a cookie (or as part of a redirect).
-
User is redirected back to
/logswith JWT included (cookie or URL param). -
logging-backend validates JWT as usual—if valid, serve logs.
B. Key features:
-
Centralizes all login and security logic in one place (identity-backend).
-
Supports extensibility: any service can use the identity-backend login page via redirect.
-
Keeps logging-backend stateless: just validates JWT.
2. Minimal Implementation Roadmap
A. identity-backend: Add User Login + Login UI
-
Implement
/loginendpoint (GET = serve login page, POST = process credentials). -
On success, issue JWT (same format as service tokens, but with
"sub"as username or user_id, audience as"logging-service"). -
Support
redirect_urlparam so login flow can return to caller. -
Set JWT as a secure, HTTP-only cookie, or as a URL param (your choice, but cookie is preferred for UX).
Example login flow:
-
User goes to
/identity-backend/login?redirect_url=https://aurorahours.com/logging-backend/logs -
After successful login, user is redirected to the original page, with JWT in a cookie.
B. logging-backend: Require User JWT for Log Viewer
-
For browser
/logsendpoint, check for JWT in cookie (if present), else check Authorization header (for API/bots). -
If no valid JWT, redirect to
/identity-backend/login?... -
Validate JWT as before (must have correct audience, issuer, not expired).
3. Your Next Steps
Step 1: Add User Login to identity-backend
-
Basic username/password (can be a static dict, SQLite, or a simple in-memory check for MVP).
-
Issue JWT with subject = username, audience = requested microservice.
Step 2: Implement /login page in identity-backend
-
Simple HTML form (GET = render form, POST = process login).
-
On success: issue JWT (as cookie), redirect to
redirect_urlparam.
Step 3: Update logging-backend /logs to support JWT in Cookie
-
On page request, check for JWT in cookie (fallback to Authorization header for APIs).
-
If JWT missing/invalid: redirect to identity-backend login (with proper
redirect_url).
Step 4: (Optional, but recommended)
-
Add logout endpoint (clear cookie).
-
Support refresh tokens (for longer-lived sessions).
Sample Sequence Diagram
User (browser) -> GET /logging-backend/logs
-> [no JWT] -> redirect to /identity-backend/login?redirect_url=...
-> [enters creds]
-> [POST login] -> /identity-backend/login
-> [success] -> Set JWT cookie, redirect back to /logging-backend/logs
User (browser) -> GET /logging-backend/logs (now with JWT)
-> [JWT valid] -> Show logs
Recommended JWT Format (User Session)
{
"iss": "identity-backend",
"sub": "saad", // user
"aud": "logging-service",
"iat": ...,
"exp": ...
}
This matches your current token structure—only sub is now a username instead of a service.
4. Code Sample: identity-backend Login Route (MVP)
# In identity-backend/app.py
from flask import Flask, request, jsonify, redirect, render_template_string, make_response
import jwt, datetime
# Add a fake user for MVP
USERS = {"saad": "password123"}
@app.route("/login", methods=["GET", "POST"])
def login():
redirect_url = request.args.get("redirect_url", "/")
if request.method == "GET":
# Serve simple HTML login form
return render_template_string("""
<form method="post">
Username: <input name="username"><br>
Password: <input name="password" type="password"><br>
<input type="hidden" name="redirect_url" value="{{ redirect_url }}">
<button type="submit">Login</button>
</form>
""", redirect_url=redirect_url)
else:
username = request.form["username"]
password = request.form["password"]
if USERS.get(username) != password:
return "Login failed", 401
now = datetime.datetime.utcnow()
payload = {
"iss": JWT_ISSUER,
"sub": username,
"aud": "logging-service", # or make dynamic!
"iat": now,
"exp": now + datetime.timedelta(minutes=JWT_EXPIRATION_MINUTES)
}
token = jwt.encode(payload, JWT_SECRET_KEY, algorithm="HS256")
resp = make_response(redirect(redirect_url))
resp.set_cookie("jwt", token, httponly=True, secure=True)
return resp
5. Code Sample: logging-backend JWT Handling (Browser)
from flask import request, redirect
def get_jwt():
# Prefer JWT from cookie for browser, else Authorization header for API
token = request.cookies.get("jwt")
if not token:
auth_header = request.headers.get("Authorization", "")
if auth_header.startswith("Bearer "):
token = auth_header.split(" ")[1]
return token
@app.route("/logs", methods=["GET"])
def get_logs():
token = get_jwt()
if not token:
# No token: redirect to login page
login_url = f"https://aurorahours.com/identity-backend/login?redirect_url=https://aurorahours.com/logging-backend/logs"
return redirect(login_url)
# ...proceed to validate token as before
6. Summary Table
| What | Who serves it | Auth logic | UX for browser |
|---|---|---|---|
Log viewer (/logs) |
logging-backend | Checks JWT, redirects if absent | Seamless SSO |
Login page (/login) |
identity-backend | Handles username/password | Centralized, reusable |
Ready for Implementation?
If you’re happy with this pattern, I can:
-
Write you the complete code for both changes, or
-
Walk you through how to build each step in your current repos.
Let me know how you want to proceed!
(Or if you want SPA support, OAuth, multi-microservice logins, etc.—just say the word.)
Comments
Post a Comment