Commit 7fdaca09 authored by Your Name's avatar Your Name

v0.99.32 - Fix OAuth authentication UI and restore full functionality

- Fixed duplicate authentication area in providers dashboard
- Restored full OAuth authentication with popup windows for all providers
- Added missing JavaScript authentication functions (authenticateClaude, authenticateQwen, authenticateCodex, authenticateKilo)
- Added missing backend endpoint /dashboard/providers/{provider_name}/auth/check
- Fixed import errors and attribute access for OAuth provider configs
- Fixed credential structure access for each OAuth provider type
- Fixed polling status responses (approved -> completed)
- Added human-readable expiration time formatting (days, hours, minutes, seconds)
- All OAuth flows now work with proper popup windows, polling, and status updates
parent e7663cb5
...@@ -54,7 +54,7 @@ from .auth.qwen import QwenOAuth2 ...@@ -54,7 +54,7 @@ from .auth.qwen import QwenOAuth2
from .handlers import RequestHandler, RotationHandler, AutoselectHandler from .handlers import RequestHandler, RotationHandler, AutoselectHandler
from .utils import count_messages_tokens, split_messages_into_chunks, get_max_request_tokens_for_model from .utils import count_messages_tokens, split_messages_into_chunks, get_max_request_tokens_for_model
__version__ = "0.99.31" __version__ = "0.99.32"
__all__ = [ __all__ = [
# Config # Config
"config", "config",
......
...@@ -32,6 +32,7 @@ from fastapi.templating import Jinja2Templates ...@@ -32,6 +32,7 @@ from fastapi.templating import Jinja2Templates
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
from aisbf.models import ChatCompletionRequest, ChatCompletionResponse from aisbf.models import ChatCompletionRequest, ChatCompletionResponse
from aisbf.handlers import RequestHandler, RotationHandler, AutoselectHandler from aisbf.handlers import RequestHandler, RotationHandler, AutoselectHandler
from aisbf.config import Config
from aisbf.mcp import mcp_server, MCPAuthLevel, load_mcp_config from aisbf.mcp import mcp_server, MCPAuthLevel, load_mcp_config
from aisbf.database import DatabaseRegistry from aisbf.database import DatabaseRegistry
from aisbf.cache import initialize_cache from aisbf.cache import initialize_cache
...@@ -5759,6 +5760,88 @@ async def dashboard_provider_file_delete( ...@@ -5759,6 +5760,88 @@ async def dashboard_provider_file_delete(
return JSONResponse(status_code=500, content={"error": str(e)}) return JSONResponse(status_code=500, content={"error": str(e)})
# OAuth authentication check endpoints for providers
@app.get("/dashboard/providers/{provider_name}/auth/check")
async def dashboard_provider_auth_check(request: Request, provider_name: str):
"""Check OAuth authentication status for a provider"""
auth_check = require_admin(request)
if auth_check:
return auth_check
try:
# Load current provider configuration
config = Config()
provider_config = config.providers.get(provider_name)
if not provider_config:
return JSONResponse(
status_code=404,
content={"authenticated": False, "error": f"Provider '{provider_name}' not found"}
)
provider_type = provider_config.type
if provider_type == 'claude':
from aisbf.auth.claude import ClaudeAuth
claude_config = provider_config.claude_config or {}
auth = ClaudeAuth(credentials_file=claude_config.get('credentials_file', '~/.claude_credentials.json'))
is_auth = auth.is_authenticated()
result = {"authenticated": is_auth}
if is_auth and auth.tokens and 'expires_at' in auth.tokens:
result["expires_at"] = auth.tokens['expires_at']
return JSONResponse(result)
elif provider_type == 'kilocode':
from aisbf.auth.kilo import KiloOAuth2
kilo_config = provider_config.kilo_config or {}
auth = KiloOAuth2(credentials_file=kilo_config.get('credentials_file', '~/.kilo_credentials.json'))
is_auth = auth.is_authenticated()
result = {"authenticated": is_auth}
if is_auth and auth.credentials:
expires = auth.credentials.get('expires', 0)
if expires:
result["expires_at"] = expires
return JSONResponse(result)
elif provider_type == 'qwen':
from aisbf.auth.qwen import QwenOAuth2
qwen_config = provider_config.qwen_config or {}
auth = QwenOAuth2(credentials_file=qwen_config.get('credentials_file', '~/.aisbf/qwen_credentials.json'))
is_auth = auth.is_authenticated()
result = {"authenticated": is_auth}
if is_auth and auth.credentials:
expiry_date = auth.credentials.get('expiry_date', 0)
if expiry_date:
# Convert from milliseconds to seconds
result["expires_at"] = expiry_date / 1000
return JSONResponse(result)
elif provider_type == 'codex':
from aisbf.auth.codex import CodexOAuth2
codex_config = provider_config.codex_config or {}
auth = CodexOAuth2(credentials_file=codex_config.get('credentials_file', '~/.aisbf/codex_credentials.json'))
is_auth = auth.is_authenticated()
result = {"authenticated": is_auth}
if is_auth and auth.credentials:
expires = auth.credentials.get('expires', 0)
if expires:
result["expires_at"] = expires
return JSONResponse(result)
else:
return JSONResponse(
status_code=400,
content={"authenticated": False, "error": f"Provider type '{provider_type}' does not support OAuth authentication checks"}
)
except Exception as e:
logger.error(f"Error checking auth for provider {provider_name}: {e}")
return JSONResponse(
status_code=500,
content={"authenticated": False, "error": str(e)}
)
# User-specific rotation management routes # User-specific rotation management routes
@app.get("/dashboard/user/rotations", response_class=HTMLResponse) @app.get("/dashboard/user/rotations", response_class=HTMLResponse)
async def dashboard_user_rotations(request: Request): async def dashboard_user_rotations(request: Request):
...@@ -12065,7 +12148,7 @@ async def dashboard_kilo_auth_poll(request: Request): ...@@ -12065,7 +12148,7 @@ async def dashboard_kilo_auth_poll(request: Request):
return JSONResponse({ return JSONResponse({
"success": True, "success": True,
"status": "approved", "status": "completed",
"message": "Authentication completed successfully" "message": "Authentication completed successfully"
}) })
elif result['status'] == 'pending': elif result['status'] == 'pending':
...@@ -12750,7 +12833,7 @@ async def dashboard_qwen_auth_poll(request: Request): ...@@ -12750,7 +12833,7 @@ async def dashboard_qwen_auth_poll(request: Request):
return JSONResponse({ return JSONResponse({
"success": True, "success": True,
"status": "approved", "status": "completed",
"message": "Authentication completed successfully" "message": "Authentication completed successfully"
}) })
elif result is None: elif result is None:
......
...@@ -49,7 +49,7 @@ class InstallCommand(_install): ...@@ -49,7 +49,7 @@ class InstallCommand(_install):
setup( setup(
name="aisbf", name="aisbf",
version="0.99.31", version="0.99.32",
author="AISBF Contributors", author="AISBF Contributors",
author_email="stefy@nexlab.net", author_email="stefy@nexlab.net",
description="AISBF - AI Service Broker Framework || AI Should Be Free - A modular proxy server for managing multiple AI provider integrations", description="AISBF - AI Service Broker Framework || AI Should Be Free - A modular proxy server for managing multiple AI provider integrations",
......
This diff is collapsed.
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