fix(auth): ensure JWT sub claim is RFC 7519 compliant string
- Change TokenPayload.sub type from int to str per JWT RFC 7519 - Add user_id property to TokenPayload for int conversion - Update token creation to serialize user_id as string - Update token consumers to use payload.user_id - Change dashboard port from 3000 to 8080 - Add pydantic[email] for email validation - Update default admin email to admin@sparc.dev 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -236,7 +236,7 @@ async def refresh_token(request: RefreshRequest):
|
||||
)
|
||||
|
||||
db = get_db_client()
|
||||
user = db.get_user_by_id(payload.sub)
|
||||
user = db.get_user_by_id(payload.user_id)
|
||||
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
|
||||
+9
-4
@@ -24,12 +24,17 @@ security = HTTPBearer()
|
||||
class TokenPayload(BaseModel):
|
||||
"""JWT token payload."""
|
||||
|
||||
sub: int # user_id
|
||||
sub: str # user_id as string (JWT RFC 7519 requires sub to be a string)
|
||||
email: str
|
||||
role: str
|
||||
exp: datetime
|
||||
type: str # "access" or "refresh"
|
||||
|
||||
@property
|
||||
def user_id(self) -> int:
|
||||
"""Get user_id as integer."""
|
||||
return int(self.sub)
|
||||
|
||||
|
||||
class TokenResponse(BaseModel):
|
||||
"""Token response model."""
|
||||
@@ -61,7 +66,7 @@ def create_access_token(user_id: int, email: str, role: str) -> str:
|
||||
"""
|
||||
expire = datetime.now(timezone.utc) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||
payload = {
|
||||
"sub": user_id,
|
||||
"sub": str(user_id),
|
||||
"email": email,
|
||||
"role": role,
|
||||
"exp": expire,
|
||||
@@ -83,7 +88,7 @@ def create_refresh_token(user_id: int, email: str, role: str) -> str:
|
||||
"""
|
||||
expire = datetime.now(timezone.utc) + timedelta(days=REFRESH_TOKEN_EXPIRE_DAYS)
|
||||
payload = {
|
||||
"sub": user_id,
|
||||
"sub": str(user_id),
|
||||
"email": email,
|
||||
"role": role,
|
||||
"exp": expire,
|
||||
@@ -166,7 +171,7 @@ async def get_current_user(
|
||||
)
|
||||
|
||||
db = get_db_client()
|
||||
user = db.get_user_by_id(payload.sub)
|
||||
user = db.get_user_by_id(payload.user_id)
|
||||
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ services:
|
||||
build: ./frontend
|
||||
container_name: sparc-dashboard
|
||||
ports:
|
||||
- "3000:80"
|
||||
- "8080:80"
|
||||
depends_on:
|
||||
- api
|
||||
restart: unless-stopped
|
||||
|
||||
@@ -8,6 +8,7 @@ openai
|
||||
psycopg2-binary
|
||||
fastapi
|
||||
uvicorn[standard]
|
||||
pydantic[email]
|
||||
httpx
|
||||
numpy
|
||||
pandas
|
||||
|
||||
@@ -19,7 +19,7 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
from SPARC import config
|
||||
from SPARC.database import DatabaseClient
|
||||
|
||||
DEFAULT_ADMIN_EMAIL = "admin@sparc.local"
|
||||
DEFAULT_ADMIN_EMAIL = "admin@sparc.dev"
|
||||
|
||||
|
||||
def generate_password(length: int = 16) -> str:
|
||||
|
||||
Reference in New Issue
Block a user