Skip to content

Commit 459d2c9

Browse files
committed
Added refresh token logic
1 parent 9f25216 commit 459d2c9

3 files changed

Lines changed: 64 additions & 4 deletions

File tree

src/auth/ibm_auth.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
IBM_JWT_PUBLIC_KEY_URL is configured.
77
fetch_ibm_public_key — fetch and cache IBM's public key PEM.
88
"""
9+
import asyncio
10+
911
import httpx
1012
import jwt
1113
from cryptography.hazmat.primitives.serialization import load_pem_public_key
1214

15+
from config.settings import PLATFORM_REFRESH_URL
1316
from utils.logging_config import get_logger
1417

1518
logger = get_logger(__name__)
@@ -88,3 +91,30 @@ def validate_ibm_jwt(token: str, public_key) -> dict | None:
8891
except jwt.InvalidTokenError as exc:
8992
logger.warning("IBM JWT validation failed", error=str(exc))
9093
return None
94+
95+
async def refresh_ibm_jwt(token: str) -> str | None:
96+
"""Refresh the IBM JWT token using the configured PLATFORM_REFRESH_URL."""
97+
if not PLATFORM_REFRESH_URL:
98+
return None
99+
100+
headers = {
101+
"Authorization": f"Bearer {token}",
102+
"User-Agent": "curl/7.64.1"
103+
}
104+
105+
async with httpx.AsyncClient() as client:
106+
for attempt in range(10):
107+
try:
108+
resp = await client.post(PLATFORM_REFRESH_URL, headers=headers, timeout=30.0)
109+
if resp.status_code == 200:
110+
data = resp.json()
111+
new_token = data.get("token") or data.get("access_token") or data.get("refresh_token") or resp.text.strip().strip('"')
112+
if '.' in new_token:
113+
logger.info("Successfully refreshed IBM JWT token.")
114+
return new_token
115+
except Exception as e:
116+
logger.warning(f"Failed to refresh IBM token (attempt {attempt + 1}): {e}")
117+
118+
await asyncio.sleep(10)
119+
120+
return None

src/config/settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@
6363
IBM_AUTH_ENABLED = os.getenv("IBM_AUTH_ENABLED", "false").lower() in ("true", "1", "yes")
6464
PLATFORM_USERNAME = os.getenv("PLATFORM_USERNAME")
6565
PLATFORM_PASSWORD = os.getenv("PLATFORM_PASSWORD")
66+
PLATFORM_REFRESH_URL = os.getenv("PLATFORM_REFRESH_URL")
67+
PLATFORM_REFRESH_PERIOD = get_env_int("PLATFORM_REFRESH_PERIOD", 60)
6668
IBM_JWT_PUBLIC_KEY_URL = os.getenv("IBM_JWT_PUBLIC_KEY_URL", "")
6769
IBM_SESSION_COOKIE_NAME = os.getenv("IBM_SESSION_COOKIE_NAME", "ibm-openrag-session")
6870
IBM_CREDENTIALS_HEADER = os.getenv("IBM_CREDENTIALS_HEADER", "X-IBM-LH-Credentials")

src/dependencies.py

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ async def my_endpoint(
2121
from typing import Optional
2222

2323
from cachetools import TTLCache
24-
from fastapi import Depends, HTTPException, Request
24+
from fastapi import Depends, HTTPException, Request, Response
2525
from sqlalchemy.ext.asyncio import AsyncSession
2626

2727
from session_manager import User
@@ -342,7 +342,7 @@ async def _dep(
342342
# ─────────────────────────────────────────────
343343

344344

345-
async def _get_ibm_user(request: Request, required: bool) -> Optional["User"]:
345+
async def _get_ibm_user(request: Request, response: Response, required: bool) -> Optional["User"]:
346346
"""Authenticate via IBM AMS.
347347
348348
0. X-IBM-LH-Credentials header (configurable via IBM_CREDENTIALS_HEADER) —
@@ -407,6 +407,32 @@ async def _get_ibm_user(request: Request, required: bool) -> Optional["User"]:
407407
user_id = claims.get("username", sub)
408408
email = claims.get("username", sub)
409409
name = claims.get("display_name", claims.get("username", sub))
410+
411+
exp = claims.get("exp")
412+
if exp:
413+
import datetime
414+
415+
from config.settings import PLATFORM_REFRESH_PERIOD
416+
417+
now = datetime.datetime.now(datetime.UTC).timestamp()
418+
if exp - now < PLATFORM_REFRESH_PERIOD:
419+
logger.info("IBM JWT token is expiring soon, attempting refresh...")
420+
new_token = await ibm_auth.refresh_ibm_jwt(ibm_token)
421+
if new_token:
422+
ibm_token = new_token
423+
response.set_cookie(
424+
key=IBM_SESSION_COOKIE_NAME,
425+
value=new_token,
426+
httponly=True,
427+
secure=True,
428+
samesite="lax",
429+
)
430+
logger.info("Successfully refreshed IBM JWT token and updated cookie.")
431+
else:
432+
if now >= exp:
433+
if required:
434+
raise HTTPException(status_code=401, detail="IBM session expired. Please log in again.")
435+
return None
410436

411437
if lh_credentials and lh_credentials.strip() != "":
412438
logger.debug("[AUTH] IBM LH credentials found in request headers")
@@ -518,6 +544,7 @@ async def _get_ibm_user(request: Request, required: bool) -> Optional["User"]:
518544

519545
async def get_current_user(
520546
request: Request,
547+
response: Response,
521548
session_manager=Depends(get_session_manager),
522549
) -> User:
523550
"""
@@ -532,7 +559,7 @@ async def get_current_user(
532559
# IBM AMS cookie auth takes priority when enabled
533560
if IBM_AUTH_ENABLED:
534561
logger.debug("[AUTH] IBM auth mode enabled, getting current user")
535-
user = await _get_ibm_user(request, required=True)
562+
user = await _get_ibm_user(request, response, required=True)
536563
if user and user.user_id and user.user_id not in session_manager.users:
537564
session_manager.users[user.user_id] = user
538565
return await _attach_db_user_id(request, user)
@@ -560,6 +587,7 @@ async def get_current_user(
560587

561588
async def get_optional_user(
562589
request: Request,
590+
response: Response,
563591
session_manager=Depends(get_session_manager),
564592
) -> User | None:
565593
"""
@@ -574,7 +602,7 @@ async def get_optional_user(
574602
# IBM AMS cookie auth takes priority when enabled
575603
if IBM_AUTH_ENABLED:
576604
logger.debug("[AUTH] IBM auth mode enabled, getting optional user")
577-
user = await _get_ibm_user(request, required=False)
605+
user = await _get_ibm_user(request, response, required=False)
578606
if user and user.user_id and user.user_id not in session_manager.users:
579607
session_manager.users[user.user_id] = user
580608
if user:

0 commit comments

Comments
 (0)