forked from 0xWheatyz/SPARC
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()
|
db = get_db_client()
|
||||||
user = db.get_user_by_id(payload.sub)
|
user = db.get_user_by_id(payload.user_id)
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|||||||
+9
-4
@@ -24,12 +24,17 @@ security = HTTPBearer()
|
|||||||
class TokenPayload(BaseModel):
|
class TokenPayload(BaseModel):
|
||||||
"""JWT token payload."""
|
"""JWT token payload."""
|
||||||
|
|
||||||
sub: int # user_id
|
sub: str # user_id as string (JWT RFC 7519 requires sub to be a string)
|
||||||
email: str
|
email: str
|
||||||
role: str
|
role: str
|
||||||
exp: datetime
|
exp: datetime
|
||||||
type: str # "access" or "refresh"
|
type: str # "access" or "refresh"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def user_id(self) -> int:
|
||||||
|
"""Get user_id as integer."""
|
||||||
|
return int(self.sub)
|
||||||
|
|
||||||
|
|
||||||
class TokenResponse(BaseModel):
|
class TokenResponse(BaseModel):
|
||||||
"""Token response model."""
|
"""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)
|
expire = datetime.now(timezone.utc) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||||
payload = {
|
payload = {
|
||||||
"sub": user_id,
|
"sub": str(user_id),
|
||||||
"email": email,
|
"email": email,
|
||||||
"role": role,
|
"role": role,
|
||||||
"exp": expire,
|
"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)
|
expire = datetime.now(timezone.utc) + timedelta(days=REFRESH_TOKEN_EXPIRE_DAYS)
|
||||||
payload = {
|
payload = {
|
||||||
"sub": user_id,
|
"sub": str(user_id),
|
||||||
"email": email,
|
"email": email,
|
||||||
"role": role,
|
"role": role,
|
||||||
"exp": expire,
|
"exp": expire,
|
||||||
@@ -166,7 +171,7 @@ async def get_current_user(
|
|||||||
)
|
)
|
||||||
|
|
||||||
db = get_db_client()
|
db = get_db_client()
|
||||||
user = db.get_user_by_id(payload.sub)
|
user = db.get_user_by_id(payload.user_id)
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|||||||
+1
-1
@@ -53,7 +53,7 @@ services:
|
|||||||
build: ./frontend
|
build: ./frontend
|
||||||
container_name: sparc-dashboard
|
container_name: sparc-dashboard
|
||||||
ports:
|
ports:
|
||||||
- "3000:80"
|
- "8080:80"
|
||||||
depends_on:
|
depends_on:
|
||||||
- api
|
- api
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ openai
|
|||||||
psycopg2-binary
|
psycopg2-binary
|
||||||
fastapi
|
fastapi
|
||||||
uvicorn[standard]
|
uvicorn[standard]
|
||||||
|
pydantic[email]
|
||||||
httpx
|
httpx
|
||||||
numpy
|
numpy
|
||||||
pandas
|
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 import config
|
||||||
from SPARC.database import DatabaseClient
|
from SPARC.database import DatabaseClient
|
||||||
|
|
||||||
DEFAULT_ADMIN_EMAIL = "admin@sparc.local"
|
DEFAULT_ADMIN_EMAIL = "admin@sparc.dev"
|
||||||
|
|
||||||
|
|
||||||
def generate_password(length: int = 16) -> str:
|
def generate_password(length: int = 16) -> str:
|
||||||
|
|||||||
Reference in New Issue
Block a user