Compare commits

...

3 Commits

Author SHA1 Message Date
Robert Brennan
469059eaf8 Update openhands/server/listen.py 2024-11-08 15:30:11 -05:00
openhands
9888184289 Add JWT signing to GitHub auth cookie
- Sign GitHub auth cookie with JWT using config.jwt_secret
- Add expiration time to JWT payload
- Validate JWT signature and expiration in middleware
- Maintain backward compatibility with X-GitHub-Token header
2024-11-08 20:28:37 +00:00
openhands
3356753f79 Add cookie-based GitHub authentication caching
- Add cookie in /authenticate endpoint with 1-hour expiration
- Check for cookie in attach_session middleware before calling GitHub API
- Support cookie auth in WebSocket endpoint
- Maintain backward compatibility with X-GitHub-Token header
2024-11-08 20:23:07 +00:00

View File

@@ -2,6 +2,7 @@ import asyncio
import os
import re
import tempfile
import time
import uuid
import warnings
from contextlib import asynccontextmanager
@@ -60,7 +61,7 @@ from openhands.events.serialization import event_to_dict
from openhands.events.stream import AsyncEventStreamWrapper
from openhands.llm import bedrock
from openhands.runtime.base import Runtime
from openhands.server.auth import get_sid_from_token, sign_token
from openhands.server.auth import get_sid_from_token, sign_token, jwt_encode, jwt_decode
from openhands.server.middleware import LocalhostCORSMiddleware, NoCacheMiddleware
from openhands.server.session import SessionManager
@@ -204,12 +205,34 @@ async def attach_session(request: Request, call_next):
response = await call_next(request)
return response
github_token = request.headers.get('X-GitHub-Token')
if not await authenticate_github_user(github_token):
return JSONResponse(
status_code=status.HTTP_401_UNAUTHORIZED,
content={'error': 'Not authenticated'},
)
# First check for auth cookie
signed_token = request.cookies.get('github_auth')
github_token = None
if signed_token:
try:
# Verify and decode the JWT token
cookie_data = jwt_decode(signed_token, config.jwt_secret)
github_token = cookie_data.get('github_token')
except Exception:
# If token is invalid or expired, ignore it
github_token = None
# If no valid cookie, fall back to header
if not github_token:
github_token = request.headers.get('X-GitHub-Token')
# If no header token either, return error
if not github_token:
return JSONResponse(
status_code=status.HTTP_401_UNAUTHORIZED,
content={'error': 'Not authenticated'},
)
# If using header token, verify with GitHub
if not await authenticate_github_user(github_token):
return JSONResponse(
status_code=status.HTTP_401_UNAUTHORIZED,
content={'error': 'Not authenticated'},
)
if not request.headers.get('Authorization'):
logger.warning('Missing Authorization header')
@@ -864,10 +887,25 @@ async def authenticate(request: Request):
content={'error': 'Not authorized via GitHub waitlist'},
)
response = JSONResponse(
status_code=status.HTTP_200_OK, content={'message': 'User authenticated'}
)
# Create a signed JWT token with 1-hour expiration
cookie_data = {
'github_token': token,
'exp': int(time.time()) + 3600 # 1 hour expiration
}
signed_token = jwt_encode(cookie_data, config.jwt_secret)
response = JSONResponse(
status_code=status.HTTP_200_OK, content={'message': 'User authenticated'})
# Set secure cookie with signed token
response.set_cookie(
key="github_auth",
value=signed_token,
max_age=3600, # 1 hour in seconds
httponly=True,
secure=True,
samesite="strict"
)
return response