diff --git a/app/auth/providers.py b/app/auth/providers.py index 609f4d0..38f6c8f 100644 --- a/app/auth/providers.py +++ b/app/auth/providers.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +import time from abc import ABC, abstractmethod from urllib.parse import urlencode @@ -22,7 +23,7 @@ class OAuthProvider(ABC): """Whether this provider is configured.""" @abstractmethod - def get_authorize_url(self, state: str, redirect_uri: str | None = None) -> str: + def get_authorize_url(self, state: str, redirect_uri: str | None = None, force_login: bool = False) -> str: """Build the authorization URL.""" @abstractmethod @@ -53,16 +54,18 @@ class GiteaProvider(OAuthProvider): def is_enabled(self) -> bool: return bool(self.client_id and self.client_secret) - def get_authorize_url(self, state: str, redirect_uri: str | None = None) -> str: - return ( - f"{self.base}/login/oauth/authorize?" - + urlencode({ - "client_id": self.client_id, - "redirect_uri": redirect_uri or self.redirect_uri, - "response_type": "code", - "state": state, - }) - ) + def get_authorize_url(self, state: str, redirect_uri: str | None = None, force_login: bool = False) -> str: + params = { + "client_id": self.client_id, + "redirect_uri": redirect_uri or self.redirect_uri, + "response_type": "code", + "state": state, + } + if force_login: + # Gitea supports prompt=login param (undocumented but works) + # If not, fallback: add _force= timestamp cache-buster + params["_force"] = str(int(time.time())) + return f"{self.base}/login/oauth/authorize?" + urlencode(params) async def exchange_code(self, code: str, redirect_uri: str | None = None) -> dict | None: url = f"{self.base}/login/oauth/access_token" @@ -143,7 +146,7 @@ class GitHubProvider(OAuthProvider): def is_enabled(self) -> bool: return bool(self.client_id and self.client_secret) - def get_authorize_url(self, state: str, redirect_uri: str | None = None) -> str: + def get_authorize_url(self, state: str, redirect_uri: str | None = None, force_login: bool = False) -> str: return ( f"{self.authorize_url}?" + urlencode({ diff --git a/app/routers/auth.py b/app/routers/auth.py index 52c4ec4..efe77fa 100644 --- a/app/routers/auth.py +++ b/app/routers/auth.py @@ -121,7 +121,7 @@ async def login(request: Request, provider: str = Query("gitea")): # Dynamic redirect URI based on incoming Host header host = request.headers.get("host", "localhost:8080") dynamic_redirect_uri = f"http://{host}/auth/callback" - auth_url = oauth_provider.get_authorize_url(state, redirect_uri=dynamic_redirect_uri) + auth_url = oauth_provider.get_authorize_url(state, redirect_uri=dynamic_redirect_uri, force_login=(mode == "link")) return RedirectResponse(url=auth_url, status_code=302)