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: ...@@ -152,12 +152,18 @@ class ClaudeAuth:
- If save_callback is provided, use it (database save for user providers) - If save_callback is provided, use it (database save for user providers)
- Otherwise, save to file with file locking to prevent race conditions - Otherwise, save to file with file locking to prevent race conditions
""" """
# Normalize and prepare token data
self.tokens = 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: if self._save_callback:
# User provider: ONLY use callback, NO file fallback EVER # User provider: ONLY use callback, NO file fallback EVER
try: try:
self._save_callback({'tokens': data}) self._save_callback({'tokens': self.tokens})
logger.info("ClaudeAuth: Saved credentials via callback") logger.info("ClaudeAuth: Saved credentials via callback")
return return
except Exception as e: except Exception as e:
...@@ -167,12 +173,6 @@ class ClaudeAuth: ...@@ -167,12 +173,6 @@ class ClaudeAuth:
# Admin/global provider ONLY: save to file # Admin/global provider ONLY: save to file
try: 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 # Ensure directory exists
self.credentials_file.parent.mkdir(parents=True, exist_ok=True) self.credentials_file.parent.mkdir(parents=True, exist_ok=True)
......
...@@ -132,8 +132,12 @@ class ClaudeProviderHandler(BaseProviderHandler): ...@@ -132,8 +132,12 @@ class ClaudeProviderHandler(BaseProviderHandler):
skip_initial_load=True, skip_initial_load=True,
save_callback=lambda creds: self._save_auth_to_db(creds) save_callback=lambda creds: self._save_auth_to_db(creds)
) )
# Set tokens directly from database # Set tokens directly from database
auth.tokens = db_creds['credentials'].get('tokens', {}) 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 import logging
logging.getLogger(__name__).info(f"ClaudeProviderHandler: Loaded credentials from database for user {self.user_id}") logging.getLogger(__name__).info(f"ClaudeProviderHandler: Loaded credentials from database for user {self.user_id}")
return auth return auth
......
...@@ -6217,7 +6217,34 @@ async def dashboard_provider_auth_check(request: Request, provider_name: str): ...@@ -6217,7 +6217,34 @@ async def dashboard_provider_auth_check(request: Request, provider_name: str):
claude_config = provider_config.get('claude_config', {}) claude_config = provider_config.get('claude_config', {})
else: else:
claude_config = provider_config.claude_config or {} 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() is_auth = auth.is_authenticated()
result = {"authenticated": is_auth} result = {"authenticated": is_auth}
if is_auth and auth.tokens and 'expires_at' in auth.tokens: 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): ...@@ -6231,7 +6258,31 @@ async def dashboard_provider_auth_check(request: Request, provider_name: str):
kilo_config = provider_config.get('kilo_config', {}) kilo_config = provider_config.get('kilo_config', {})
else: else:
kilo_config = provider_config.kilo_config or {} 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() is_auth = auth.is_authenticated()
result = {"authenticated": is_auth} result = {"authenticated": is_auth}
if is_auth and auth.credentials: if is_auth and auth.credentials:
...@@ -6247,7 +6298,31 @@ async def dashboard_provider_auth_check(request: Request, provider_name: str): ...@@ -6247,7 +6298,31 @@ async def dashboard_provider_auth_check(request: Request, provider_name: str):
qwen_config = provider_config.get('qwen_config', {}) qwen_config = provider_config.get('qwen_config', {})
else: else:
qwen_config = provider_config.qwen_config or {} 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() is_auth = auth.is_authenticated()
result = {"authenticated": is_auth} result = {"authenticated": is_auth}
if is_auth and auth.credentials: if is_auth and auth.credentials:
...@@ -6264,7 +6339,31 @@ async def dashboard_provider_auth_check(request: Request, provider_name: str): ...@@ -6264,7 +6339,31 @@ async def dashboard_provider_auth_check(request: Request, provider_name: str):
codex_config = provider_config.get('codex_config', {}) codex_config = provider_config.get('codex_config', {})
else: else:
codex_config = provider_config.codex_config or {} 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() is_auth = auth.is_authenticated()
result = {"authenticated": is_auth} result = {"authenticated": is_auth}
if is_auth and auth.credentials: 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