Mark-Lasfar
commited on
Commit
·
0effe0c
1
Parent(s):
448d967
Update backend and server frontend for OAuth JSON response, client-side navigation, and add .gitignore
Browse files- api/auth.py +29 -9
- requirements.txt +2 -1
- templates/login.html +49 -45
api/auth.py
CHANGED
|
@@ -4,7 +4,7 @@ from httpx_oauth.clients.google import GoogleOAuth2
|
|
| 4 |
from httpx_oauth.clients.github import GitHubOAuth2
|
| 5 |
from fastapi_users.manager import BaseUserManager, IntegerIDMixin
|
| 6 |
from fastapi import Depends, Request, FastAPI, Response
|
| 7 |
-
from fastapi.responses import JSONResponse
|
| 8 |
from sqlalchemy.ext.asyncio import AsyncSession
|
| 9 |
from sqlalchemy import select
|
| 10 |
from fastapi_users.models import UP
|
|
@@ -200,6 +200,7 @@ async def custom_oauth_callback(
|
|
| 200 |
oauth_client=Depends(lambda: google_oauth_client),
|
| 201 |
redirect_url: str = GOOGLE_REDIRECT_URL,
|
| 202 |
response: Response = None,
|
|
|
|
| 203 |
):
|
| 204 |
logger.debug(f"Processing Google callback with code: {code}, state: {state}")
|
| 205 |
try:
|
|
@@ -246,10 +247,19 @@ async def custom_oauth_callback(
|
|
| 246 |
secure=True,
|
| 247 |
)
|
| 248 |
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 253 |
except Exception as e:
|
| 254 |
logger.error(f"Error in Google OAuth callback: {str(e)}")
|
| 255 |
return JSONResponse(content={"detail": str(e)}, status_code=400)
|
|
@@ -261,6 +271,7 @@ async def custom_github_oauth_callback(
|
|
| 261 |
oauth_client=Depends(lambda: github_oauth_client),
|
| 262 |
redirect_url: str = GITHUB_REDIRECT_URL,
|
| 263 |
response: Response = None,
|
|
|
|
| 264 |
):
|
| 265 |
logger.debug(f"Processing GitHub callback with code: {code}, state: {state}")
|
| 266 |
try:
|
|
@@ -325,10 +336,19 @@ async def custom_github_oauth_callback(
|
|
| 325 |
secure=True,
|
| 326 |
)
|
| 327 |
|
| 328 |
-
|
| 329 |
-
|
| 330 |
-
|
| 331 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 332 |
except Exception as e:
|
| 333 |
logger.error(f"Error in GitHub OAuth callback: {str(e)}")
|
| 334 |
return JSONResponse(content={"detail": str(e)}, status_code=400)
|
|
|
|
| 4 |
from httpx_oauth.clients.github import GitHubOAuth2
|
| 5 |
from fastapi_users.manager import BaseUserManager, IntegerIDMixin
|
| 6 |
from fastapi import Depends, Request, FastAPI, Response
|
| 7 |
+
from fastapi.responses import JSONResponse, RedirectResponse
|
| 8 |
from sqlalchemy.ext.asyncio import AsyncSession
|
| 9 |
from sqlalchemy import select
|
| 10 |
from fastapi_users.models import UP
|
|
|
|
| 200 |
oauth_client=Depends(lambda: google_oauth_client),
|
| 201 |
redirect_url: str = GOOGLE_REDIRECT_URL,
|
| 202 |
response: Response = None,
|
| 203 |
+
request: Request = None,
|
| 204 |
):
|
| 205 |
logger.debug(f"Processing Google callback with code: {code}, state: {state}")
|
| 206 |
try:
|
|
|
|
| 247 |
secure=True,
|
| 248 |
)
|
| 249 |
|
| 250 |
+
# تحقق إذا كان الطلب من التطبيق (Capacitor) أو الويب
|
| 251 |
+
is_app = request.headers.get("X-Capacitor-App", False)
|
| 252 |
+
|
| 253 |
+
if is_app:
|
| 254 |
+
# للتطبيق: إرجاع JSON مع الـ token
|
| 255 |
+
return JSONResponse(content={
|
| 256 |
+
"message": "Google login successful",
|
| 257 |
+
"access_token": token
|
| 258 |
+
}, status_code=200)
|
| 259 |
+
else:
|
| 260 |
+
# للويب: إرجاع redirect إلى /chat
|
| 261 |
+
return RedirectResponse(url="/chat", status_code=303)
|
| 262 |
+
|
| 263 |
except Exception as e:
|
| 264 |
logger.error(f"Error in Google OAuth callback: {str(e)}")
|
| 265 |
return JSONResponse(content={"detail": str(e)}, status_code=400)
|
|
|
|
| 271 |
oauth_client=Depends(lambda: github_oauth_client),
|
| 272 |
redirect_url: str = GITHUB_REDIRECT_URL,
|
| 273 |
response: Response = None,
|
| 274 |
+
request: Request = None,
|
| 275 |
):
|
| 276 |
logger.debug(f"Processing GitHub callback with code: {code}, state: {state}")
|
| 277 |
try:
|
|
|
|
| 336 |
secure=True,
|
| 337 |
)
|
| 338 |
|
| 339 |
+
# تحقق إذا كان الطلب من التطبيق (Capacitor) أو الويب
|
| 340 |
+
is_app = request.headers.get("X-Capacitor-App", False)
|
| 341 |
+
|
| 342 |
+
if is_app:
|
| 343 |
+
# للتطبيق: إرجاع JSON مع الـ token
|
| 344 |
+
return JSONResponse(content={
|
| 345 |
+
"message": "GitHub login successful",
|
| 346 |
+
"access_token": token
|
| 347 |
+
}, status_code=200)
|
| 348 |
+
else:
|
| 349 |
+
# للويب: إرجاع redirect إلى /chat
|
| 350 |
+
return RedirectResponse(url="/chat", status_code=303)
|
| 351 |
+
|
| 352 |
except Exception as e:
|
| 353 |
logger.error(f"Error in GitHub OAuth callback: {str(e)}")
|
| 354 |
return JSONResponse(content={"detail": str(e)}, status_code=400)
|
requirements.txt
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
fastapi==0.95.2
|
| 2 |
-
|
|
|
|
| 3 |
pydantic==1.10.13
|
| 4 |
email-validator==1.3.1
|
| 5 |
sqlalchemy[asyncio]
|
|
|
|
| 1 |
fastapi==0.95.2
|
| 2 |
+
|
| 3 |
+
fastapi-users[sqlalchemy,oauth2]==12.1.3
|
| 4 |
pydantic==1.10.13
|
| 5 |
email-validator==1.3.1
|
| 6 |
sqlalchemy[asyncio]
|
templates/login.html
CHANGED
|
@@ -568,58 +568,62 @@
|
|
| 568 |
|
| 569 |
// Check for OAuth callback on load
|
| 570 |
window.addEventListener('load', async () => {
|
| 571 |
-
|
| 572 |
-
|
| 573 |
-
|
| 574 |
-
|
| 575 |
-
|
| 576 |
-
|
| 577 |
-
|
| 578 |
-
|
| 579 |
-
|
| 580 |
-
|
| 581 |
-
|
| 582 |
-
|
| 583 |
-
|
| 584 |
-
|
| 585 |
-
|
| 586 |
-
|
| 587 |
-
|
| 588 |
-
|
| 589 |
-
|
| 590 |
-
|
| 591 |
-
|
| 592 |
-
|
| 593 |
-
|
| 594 |
-
|
| 595 |
-
|
| 596 |
-
|
| 597 |
-
|
| 598 |
-
|
| 599 |
-
|
| 600 |
-
|
| 601 |
-
|
| 602 |
-
|
| 603 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 604 |
} else {
|
| 605 |
-
throw new Error('
|
| 606 |
}
|
| 607 |
} else {
|
| 608 |
-
|
| 609 |
-
errorMsg.textContent = errorData.detail || `Failed to complete ${provider} login`;
|
| 610 |
-
errorMsg.classList.remove('hidden');
|
| 611 |
-
console.error(`Failed to complete ${provider} login:`, errorData);
|
| 612 |
}
|
| 613 |
-
}
|
| 614 |
-
|
|
|
|
| 615 |
errorMsg.classList.remove('hidden');
|
| 616 |
-
console.error(`
|
| 617 |
}
|
| 618 |
-
}
|
| 619 |
-
|
|
|
|
|
|
|
| 620 |
}
|
| 621 |
-
}
|
| 622 |
-
|
| 623 |
// Handle card details toggle
|
| 624 |
function showCardDetails(cardId) {
|
| 625 |
console.log('Showing card details:', cardId);
|
|
|
|
| 568 |
|
| 569 |
// Check for OAuth callback on load
|
| 570 |
window.addEventListener('load', async () => {
|
| 571 |
+
console.log('Page loaded, checking for auth status and OAuth callback');
|
| 572 |
+
if (!navigator.onLine) {
|
| 573 |
+
errorMsg.textContent = 'You are offline. Please connect to the internet and try again.';
|
| 574 |
+
errorMsg.classList.remove('hidden');
|
| 575 |
+
return;
|
| 576 |
+
}
|
| 577 |
+
const isAuthenticated = await checkAuthStatus();
|
| 578 |
+
if (isAuthenticated) {
|
| 579 |
+
console.log('User already authenticated, redirecting to /chat');
|
| 580 |
+
window.location.href = '/chat';
|
| 581 |
+
return;
|
| 582 |
+
}
|
| 583 |
+
|
| 584 |
+
const urlParams = new URLSearchParams(window.location.search);
|
| 585 |
+
const code = urlParams.get('code');
|
| 586 |
+
const error = urlParams.get('error');
|
| 587 |
+
if (error) {
|
| 588 |
+
errorMsg.textContent = decodeURIComponent(error);
|
| 589 |
+
errorMsg.classList.remove('hidden');
|
| 590 |
+
console.error('OAuth error from URL:', error);
|
| 591 |
+
} else if (code) {
|
| 592 |
+
console.log('OAuth code detected in URL, processing callback');
|
| 593 |
+
const provider = window.location.pathname.includes('google') ? 'google' : 'github';
|
| 594 |
+
try {
|
| 595 |
+
const response = await fetch(window.location.href, {
|
| 596 |
+
method: 'GET',
|
| 597 |
+
headers: { 'Accept': 'application/json' }
|
| 598 |
+
});
|
| 599 |
+
if (response.ok) {
|
| 600 |
+
const data = await response.json();
|
| 601 |
+
if (data.access_token) {
|
| 602 |
+
localStorage.setItem('token', data.access_token);
|
| 603 |
+
console.log(`${provider} login successful, token saved`);
|
| 604 |
+
const isAuthenticated = await checkAuthStatus();
|
| 605 |
+
if (isAuthenticated) {
|
| 606 |
+
console.log('Redirecting to /chat');
|
| 607 |
+
window.location.href = '/chat';
|
| 608 |
} else {
|
| 609 |
+
throw new Error('Authentication failed after receiving token');
|
| 610 |
}
|
| 611 |
} else {
|
| 612 |
+
throw new Error('No access token received');
|
|
|
|
|
|
|
|
|
|
| 613 |
}
|
| 614 |
+
} else {
|
| 615 |
+
const errorData = await response.json();
|
| 616 |
+
errorMsg.textContent = errorData.detail || `Failed to complete ${provider} login`;
|
| 617 |
errorMsg.classList.remove('hidden');
|
| 618 |
+
console.error(`Failed to complete ${provider} login:`, errorData);
|
| 619 |
}
|
| 620 |
+
} catch (error) {
|
| 621 |
+
errorMsg.textContent = `Failed to process ${provider} login. Please try again.`;
|
| 622 |
+
errorMsg.classList.remove('hidden');
|
| 623 |
+
console.error(`Error processing ${provider} callback:`, error);
|
| 624 |
}
|
| 625 |
+
}
|
| 626 |
+
});
|
| 627 |
// Handle card details toggle
|
| 628 |
function showCardDetails(cardId) {
|
| 629 |
console.log('Showing card details:', cardId);
|