Commit a3b0269d authored by Your Name's avatar Your Name

Fix missing expires_at field in database-saved Claude credentials

parent 7b1132e4
......@@ -152,12 +152,18 @@ class ClaudeAuth:
- If save_callback is provided, use it (database save for user providers)
- Otherwise, save to file with file locking to prevent race conditions
"""
# Normalize and prepare token data
self.tokens = data
# Store id_token if received (contains account info)
if 'id_token' in data:
self.tokens['id_token'] = data['id_token']
# Add local expiry timestamp for easier checking - DO THIS FOR BOTH FILE AND DB USERS!
self.tokens['expires_at'] = time.time() + data.get('expires_in', 3600)
if self._save_callback:
# User provider: ONLY use callback, NO file fallback EVER
try:
self._save_callback({'tokens': data})
self._save_callback({'tokens': self.tokens})
logger.info("ClaudeAuth: Saved credentials via callback")
return
except Exception as e:
......@@ -167,12 +173,6 @@ class ClaudeAuth:
# Admin/global provider ONLY: save to file
try:
self.tokens = data
# Store id_token if received (contains account info)
if 'id_token' in data:
self.tokens['id_token'] = data['id_token']
# Add local expiry timestamp for easier checking
self.tokens['expires_at'] = time.time() + data.get('expires_in', 3600)
# Ensure directory exists
self.credentials_file.parent.mkdir(parents=True, exist_ok=True)
......
......@@ -132,8 +132,12 @@ class ClaudeProviderHandler(BaseProviderHandler):
skip_initial_load=True,
save_callback=lambda creds: self._save_auth_to_db(creds)
)
# Set tokens directly from database
auth.tokens = db_creds['credentials'].get('tokens', {})
# Set tokens directly from database
auth.tokens = db_creds['credentials'].get('tokens', {})
# Add expires_at if missing (for existing credentials saved before fix)
if auth.tokens and 'expires_at' not in auth.tokens and 'expires_in' in auth.tokens:
import time
auth.tokens['expires_at'] = time.time() + auth.tokens.get('expires_in', 3600)
import logging
logging.getLogger(__name__).info(f"ClaudeProviderHandler: Loaded credentials from database for user {self.user_id}")
return auth
......
......@@ -6217,7 +6217,34 @@ async def dashboard_provider_auth_check(request: Request, provider_name: str):
claude_config = provider_config.get('claude_config', {})
else:
claude_config = provider_config.claude_config or {}
auth = ClaudeAuth(credentials_file=claude_config.get('credentials_file', '~/.claude_credentials.json'))
if current_user_id is None:
# Admin user: load from file
auth = ClaudeAuth(credentials_file=claude_config.get('credentials_file', '~/.claude_credentials.json'))
else:
# Regular user: load from database
auth = ClaudeAuth(
credentials_file=claude_config.get('credentials_file', '~/.claude_credentials.json'),
skip_initial_load=True
)
# Load credentials from database
try:
from aisbf.database import get_database
db = DatabaseRegistry.get_config_database()
if db:
db_creds = db.get_user_oauth2_credentials(
user_id=current_user_id,
provider_id=provider_name,
auth_type='claude_oauth2'
)
if db_creds and db_creds.get('credentials'):
auth.tokens = db_creds['credentials'].get('tokens', {})
# Add expires_at if missing (for existing credentials saved before fix)
if auth.tokens and 'expires_at' not in auth.tokens and 'expires_in' in auth.tokens:
auth.tokens['expires_at'] = time.time() + auth.tokens.get('expires_in', 3600)
except Exception as e:
logger.warning(f"Failed to load Claude credentials from database: {e}")
is_auth = auth.is_authenticated()
result = {"authenticated": is_auth}
if is_auth and auth.tokens and 'expires_at' in auth.tokens:
......@@ -6231,7 +6258,31 @@ async def dashboard_provider_auth_check(request: Request, provider_name: str):
kilo_config = provider_config.get('kilo_config', {})
else:
kilo_config = provider_config.kilo_config or {}
auth = KiloOAuth2(credentials_file=kilo_config.get('credentials_file', '~/.kilo_credentials.json'))
if current_user_id is None:
# Admin user: load from file
auth = KiloOAuth2(credentials_file=kilo_config.get('credentials_file', '~/.kilo_credentials.json'))
else:
# Regular user: load from database
auth = KiloOAuth2(
credentials_file=kilo_config.get('credentials_file', '~/.kilo_credentials.json'),
skip_initial_load=True
)
# Load credentials from database
try:
from aisbf.database import get_database
db = DatabaseRegistry.get_config_database()
if db:
db_creds = db.get_user_oauth2_credentials(
user_id=current_user_id,
provider_id=provider_name,
auth_type='kilo_oauth2'
)
if db_creds and db_creds.get('credentials'):
auth.credentials = db_creds['credentials']
except Exception as e:
logger.warning(f"Failed to load Kilo credentials from database: {e}")
is_auth = auth.is_authenticated()
result = {"authenticated": is_auth}
if is_auth and auth.credentials:
......@@ -6247,7 +6298,31 @@ async def dashboard_provider_auth_check(request: Request, provider_name: str):
qwen_config = provider_config.get('qwen_config', {})
else:
qwen_config = provider_config.qwen_config or {}
auth = QwenOAuth2(credentials_file=qwen_config.get('credentials_file', '~/.aisbf/qwen_credentials.json'))
if current_user_id is None:
# Admin user: load from file
auth = QwenOAuth2(credentials_file=qwen_config.get('credentials_file', '~/.aisbf/qwen_credentials.json'))
else:
# Regular user: load from database
auth = QwenOAuth2(
credentials_file=qwen_config.get('credentials_file', '~/.aisbf/qwen_credentials.json'),
skip_initial_load=True
)
# Load credentials from database
try:
from aisbf.database import get_database
db = DatabaseRegistry.get_config_database()
if db:
db_creds = db.get_user_oauth2_credentials(
user_id=current_user_id,
provider_id=provider_name,
auth_type='qwen_oauth2'
)
if db_creds and db_creds.get('credentials'):
auth.credentials = db_creds['credentials']
except Exception as e:
logger.warning(f"Failed to load Qwen credentials from database: {e}")
is_auth = auth.is_authenticated()
result = {"authenticated": is_auth}
if is_auth and auth.credentials:
......@@ -6264,7 +6339,31 @@ async def dashboard_provider_auth_check(request: Request, provider_name: str):
codex_config = provider_config.get('codex_config', {})
else:
codex_config = provider_config.codex_config or {}
auth = CodexOAuth2(credentials_file=codex_config.get('credentials_file', '~/.aisbf/codex_credentials.json'))
if current_user_id is None:
# Admin user: load from file
auth = CodexOAuth2(credentials_file=codex_config.get('credentials_file', '~/.aisbf/codex_credentials.json'))
else:
# Regular user: load from database
auth = CodexOAuth2(
credentials_file=codex_config.get('credentials_file', '~/.aisbf/codex_credentials.json'),
skip_initial_load=True
)
# Load credentials from database
try:
from aisbf.database import get_database
db = DatabaseRegistry.get_config_database()
if db:
db_creds = db.get_user_oauth2_credentials(
user_id=current_user_id,
provider_id=provider_name,
auth_type='codex_oauth2'
)
if db_creds and db_creds.get('credentials'):
auth.credentials = db_creds['credentials']
except Exception as e:
logger.warning(f"Failed to load Codex credentials from database: {e}")
is_auth = auth.is_authenticated()
result = {"authenticated": is_auth}
if is_auth and auth.credentials:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment