fixed ext logins msft and google

This commit is contained in:
ValueOn AG 2025-11-06 11:42:10 +01:00
parent d7e220682d
commit 3c63488377
2 changed files with 58 additions and 15 deletions

View file

@ -14,6 +14,7 @@ from modules.shared.configuration import APP_CONFIG
from modules.interfaces.interfaceDbAppObjects import getInterface, getRootInterface
from modules.datamodels.datamodelUam import AuthAuthority, User, ConnectionStatus, UserConnection
from modules.security.auth import getCurrentUser, limiter
from modules.security.jwtService import createAccessToken, setAccessTokenCookie, createRefreshToken, setRefreshTokenCookie
from modules.shared.timezoneUtils import createExpirationTimestamp, getUtcTimestamp
# Configure logger
@ -202,7 +203,7 @@ async def login(
)
@router.get("/auth/callback")
async def auth_callback(code: str, state: str, request: Request) -> HTMLResponse:
async def auth_callback(code: str, state: str, request: Request, response: Response) -> HTMLResponse:
"""Handle Google OAuth callback"""
try:
# Import Token at function level to avoid scoping issues
@ -337,34 +338,47 @@ async def auth_callback(code: str, state: str, request: Request) -> HTMLResponse
)
# Create JWT token data (like Microsoft does)
from modules.security.jwtService import createAccessToken
jwt_token_data = {
"sub": user.username,
"mandateId": str(user.mandateId),
"userId": str(user.id),
"authenticationAuthority": AuthAuthority.GOOGLE
"authenticationAuthority": AuthAuthority.GOOGLE.value
}
# Create JWT access token
jwt_token, jwt_expires_at = createAccessToken(jwt_token_data)
# Create refresh token
refresh_token, _refresh_expires = createRefreshToken(jwt_token_data)
# Decode token to get jti for database record
from jose import jwt
from modules.security.auth import SECRET_KEY, ALGORITHM
payload = jwt.decode(jwt_token, SECRET_KEY, algorithms=[ALGORITHM])
jti = payload.get("jti")
# Create JWT token
# Create JWT token with matching id
token = Token(
id=jti,
userId=user.id, # Use local user's ID
authority=AuthAuthority.GOOGLE,
tokenAccess=jwt_token, # Use JWT token instead of Google access token
tokenRefresh=token_response.get("refresh_token", ""),
tokenType="bearer",
expiresAt=jwt_expires_at.timestamp(),
createdAt=getUtcTimestamp()
createdAt=getUtcTimestamp(),
mandateId=str(user.mandateId)
)
# Save access token (no connectionId)
appInterface = getInterface(user)
appInterface.saveAccessToken(token)
# Return success page with token data
return HTMLResponse(
# Convert token to dict and ensure proper timestamp handling
token_dict = token.model_dump()
# Create HTML response
html_response = HTMLResponse(
content=f"""
<html>
<head><title>Authentication Successful</title></head>
@ -374,7 +388,7 @@ async def auth_callback(code: str, state: str, request: Request) -> HTMLResponse
window.opener.postMessage({{
type: 'google_auth_success',
access_token: {json.dumps(token_response["access_token"])},
token_data: {json.dumps(token.model_dump())}
token_data: {json.dumps(token_dict)}
}}, '*');
}}
setTimeout(() => window.close(), 1000);
@ -383,6 +397,15 @@ async def auth_callback(code: str, state: str, request: Request) -> HTMLResponse
</html>
"""
)
# Set access token as httpOnly cookie (like local login)
# HTMLResponse inherits from Response, so we can set cookies directly on it
setAccessTokenCookie(html_response, jwt_token, expiresDelta=None)
# Set refresh token as httpOnly cookie
setRefreshTokenCookie(html_response, refresh_token)
return html_response
else:
# Handle connection flow
if not connection_id or not user_id:

View file

@ -15,7 +15,7 @@ from modules.interfaces.interfaceDbAppObjects import getInterface, getRootInterf
from modules.datamodels.datamodelUam import AuthAuthority, User, ConnectionStatus, UserConnection
from modules.datamodels.datamodelSecurity import Token
from modules.security.auth import getCurrentUser, limiter
from modules.security.jwtService import createAccessToken
from modules.security.jwtService import createAccessToken, setAccessTokenCookie, createRefreshToken, setRefreshTokenCookie
from modules.shared.timezoneUtils import createExpirationTimestamp, getUtcTimestamp
# Configure logger
@ -123,7 +123,7 @@ async def login(
)
@router.get("/auth/callback")
async def auth_callback(code: str, state: str, request: Request) -> HTMLResponse:
async def auth_callback(code: str, state: str, request: Request, response: Response) -> HTMLResponse:
"""Handle Microsoft OAuth callback"""
try:
# Parse state
@ -212,20 +212,31 @@ async def auth_callback(code: str, state: str, request: Request) -> HTMLResponse
"sub": user.username,
"mandateId": str(user.mandateId),
"userId": str(user.id),
"authenticationAuthority": AuthAuthority.MSFT
"authenticationAuthority": AuthAuthority.MSFT.value
}
# Create JWT access token
jwt_token, jwt_expires_at = createAccessToken(jwt_token_data)
# Create refresh token
refresh_token, _refresh_expires = createRefreshToken(jwt_token_data)
# Decode token to get jti for database record
from jose import jwt
from modules.security.auth import SECRET_KEY, ALGORITHM
payload = jwt.decode(jwt_token, SECRET_KEY, algorithms=[ALGORITHM])
jti = payload.get("jti")
# Create JWT token
# Create JWT token with matching id
jwt_token_obj = Token(
id=jti,
userId=user.id,
authority=AuthAuthority.MSFT,
tokenAccess=jwt_token,
tokenType="bearer",
expiresAt=jwt_expires_at.timestamp(),
createdAt=getUtcTimestamp()
createdAt=getUtcTimestamp(),
mandateId=str(user.mandateId)
)
# Save JWT access token
@ -236,8 +247,8 @@ async def auth_callback(code: str, state: str, request: Request) -> HTMLResponse
# Remove datetime conversion logic - models now handle this automatically
# The token model already returns float timestamps
# Return success page with token data
return HTMLResponse(
# Create HTML response
html_response = HTMLResponse(
content=f"""
<html>
<head><title>Authentication Successful</title></head>
@ -255,6 +266,15 @@ async def auth_callback(code: str, state: str, request: Request) -> HTMLResponse
</html>
"""
)
# Set access token as httpOnly cookie (like local login)
# HTMLResponse inherits from Response, so we can set cookies directly on it
setAccessTokenCookie(html_response, jwt_token, expiresDelta=None)
# Set refresh token as httpOnly cookie
setRefreshTokenCookie(html_response, refresh_token)
return html_response
else:
# Handle connection flow
if not connection_id or not user_id: