akhaliq HF Staff commited on
Commit
0fb9638
·
1 Parent(s): d84050d

Fix deployment: Use OAuth session tokens properly

Browse files

Key changes:
- Update MockAuth to accept username parameter
- get_auth_from_header now looks up OAuth sessions to extract access_token
- Session tokens are properly resolved to HF OAuth access tokens
- Added detailed logging throughout deployment process
- Better error handling with user-friendly messages for 401/403 errors
- Added HfApi.whoami() call to verify token and get username
- Improved error messages for authentication and permission issues

This ensures the deploy endpoint uses the proper OAuth token from the
authenticated session rather than trying to use a session UUID directly.

Files changed (1) hide show
  1. backend_api.py +67 -17
backend_api.py CHANGED
@@ -104,25 +104,18 @@ class CodeGenerationResponse(BaseModel):
104
  # Mock authentication for development
105
  # In production, integrate with HuggingFace OAuth
106
  class MockAuth:
107
- def __init__(self, token: Optional[str] = None):
108
  self.token = token
109
- # Extract username from dev token or use generic name
110
- if token and token.startswith("dev_token_"):
111
- # Extract username from dev token format: dev_token_<username>_<timestamp>
112
- parts = token.split("_")
113
- self.username = parts[2] if len(parts) > 2 else "user"
114
- else:
115
- self.username = "user" if token else None
116
 
117
  def is_authenticated(self):
118
- # Accept any token (for dev mode)
119
  return bool(self.token)
120
 
121
 
122
  def get_auth_from_header(authorization: Optional[str] = None):
123
- """Extract authentication from header"""
124
  if not authorization:
125
- return MockAuth(None)
126
 
127
  # Handle "Bearer " prefix
128
  if authorization.startswith("Bearer "):
@@ -130,7 +123,21 @@ def get_auth_from_header(authorization: Optional[str] = None):
130
  else:
131
  token = authorization
132
 
133
- return MockAuth(token)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
 
135
 
136
  @app.get("/")
@@ -473,24 +480,43 @@ async def deploy(
473
  "dev_mode": True
474
  }
475
 
476
- # Production mode with real token
477
  try:
478
  from huggingface_hub import HfApi
479
  import tempfile
480
  import uuid
481
 
482
- # Get user token from header or use server token
483
  user_token = auth.token if auth.token else os.getenv("HF_TOKEN")
484
 
485
  if not user_token:
486
- raise HTTPException(status_code=401, detail="No HuggingFace token available")
 
 
487
 
488
  # Create API client
489
  api = HfApi(token=user_token)
490
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491
  # Generate space name if not provided
492
  space_name = request.space_name or f"anycoder-{uuid.uuid4().hex[:8]}"
493
- repo_id = f"{auth.username}/{space_name}"
 
 
494
 
495
  # Map language to SDK
496
  language_to_sdk = {
@@ -565,8 +591,32 @@ async def deploy(
565
  finally:
566
  os.unlink(temp_path)
567
 
 
 
 
568
  except Exception as e:
569
- raise HTTPException(status_code=500, detail=f"Deployment failed: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
570
 
571
 
572
  @app.websocket("/ws/generate")
 
104
  # Mock authentication for development
105
  # In production, integrate with HuggingFace OAuth
106
  class MockAuth:
107
+ def __init__(self, token: Optional[str] = None, username: Optional[str] = None):
108
  self.token = token
109
+ self.username = username
 
 
 
 
 
 
110
 
111
  def is_authenticated(self):
 
112
  return bool(self.token)
113
 
114
 
115
  def get_auth_from_header(authorization: Optional[str] = None):
116
+ """Extract authentication from header or session token"""
117
  if not authorization:
118
+ return MockAuth(None, None)
119
 
120
  # Handle "Bearer " prefix
121
  if authorization.startswith("Bearer "):
 
123
  else:
124
  token = authorization
125
 
126
+ # Check if this is a session token (UUID format)
127
+ if token and "-" in token and len(token) > 20:
128
+ # Look up the session to get user info
129
+ if token in user_sessions:
130
+ session = user_sessions[token]
131
+ return MockAuth(session["access_token"], session["username"])
132
+
133
+ # Dev token format: dev_token_<username>_<timestamp>
134
+ if token and token.startswith("dev_token_"):
135
+ parts = token.split("_")
136
+ username = parts[2] if len(parts) > 2 else "user"
137
+ return MockAuth(token, username)
138
+
139
+ # Regular token (OAuth access token passed directly)
140
+ return MockAuth(token, None)
141
 
142
 
143
  @app.get("/")
 
480
  "dev_mode": True
481
  }
482
 
483
+ # Production mode with real OAuth token
484
  try:
485
  from huggingface_hub import HfApi
486
  import tempfile
487
  import uuid
488
 
489
+ # Get user token - should be the access_token from OAuth session
490
  user_token = auth.token if auth.token else os.getenv("HF_TOKEN")
491
 
492
  if not user_token:
493
+ raise HTTPException(status_code=401, detail="No HuggingFace token available. Please sign in first.")
494
+
495
+ print(f"[Deploy] Attempting deployment with token (first 10 chars): {user_token[:10]}...")
496
 
497
  # Create API client
498
  api = HfApi(token=user_token)
499
 
500
+ # Get the actual username from HuggingFace API
501
+ try:
502
+ user_info = api.whoami()
503
+ print(f"[Deploy] User info from HF API: {user_info}")
504
+ username = user_info.get("name") or user_info.get("preferred_username") or auth.username or "user"
505
+ except Exception as e:
506
+ print(f"[Deploy] Failed to get user info from HF API: {e}")
507
+ # Fallback to auth username if available
508
+ username = auth.username
509
+ if not username:
510
+ raise HTTPException(
511
+ status_code=401,
512
+ detail="Failed to verify HuggingFace account. Please sign in again."
513
+ )
514
+
515
  # Generate space name if not provided
516
  space_name = request.space_name or f"anycoder-{uuid.uuid4().hex[:8]}"
517
+ repo_id = f"{username}/{space_name}"
518
+
519
+ print(f"[Deploy] Creating/updating space: {repo_id}")
520
 
521
  # Map language to SDK
522
  language_to_sdk = {
 
591
  finally:
592
  os.unlink(temp_path)
593
 
594
+ except HTTPException:
595
+ # Re-raise HTTP exceptions as-is
596
+ raise
597
  except Exception as e:
598
+ # Log the full error for debugging
599
+ import traceback
600
+ error_details = traceback.format_exc()
601
+ print(f"[Deploy] Deployment error: {error_details}")
602
+
603
+ # Provide user-friendly error message
604
+ error_msg = str(e)
605
+ if "401" in error_msg or "Unauthorized" in error_msg:
606
+ raise HTTPException(
607
+ status_code=401,
608
+ detail="Authentication failed. Please sign in again with HuggingFace."
609
+ )
610
+ elif "403" in error_msg or "Forbidden" in error_msg:
611
+ raise HTTPException(
612
+ status_code=403,
613
+ detail="Permission denied. Your HuggingFace token may not have the required permissions (manage-repos scope)."
614
+ )
615
+ else:
616
+ raise HTTPException(
617
+ status_code=500,
618
+ detail=f"Deployment failed: {error_msg}"
619
+ )
620
 
621
 
622
  @app.websocket("/ws/generate")