feat: force Gitea ré-auth en mode link (_force timestamp)
FlowDeck CI / test (push) Failing after 4s
FlowDeck CI / docker (push) Has been skipped

Ajout d'un paramètre _force avec timestamp dans l'URL d'autorisation
quand mode=link, pour forcer Gitea à ne pas utiliser le cache.

NOTE: Gitea ne supporte pas prompt=login. Si auto-approve persiste,
il faudra ajouter un champ token manuel en fallback.
This commit is contained in:
2026-07-13 22:18:31 -04:00
parent 06bf016392
commit f25c8ebaf0
2 changed files with 16 additions and 13 deletions
+15 -12
View File
@@ -3,6 +3,7 @@
from __future__ import annotations from __future__ import annotations
import logging import logging
import time
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from urllib.parse import urlencode from urllib.parse import urlencode
@@ -22,7 +23,7 @@ class OAuthProvider(ABC):
"""Whether this provider is configured.""" """Whether this provider is configured."""
@abstractmethod @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.""" """Build the authorization URL."""
@abstractmethod @abstractmethod
@@ -53,16 +54,18 @@ class GiteaProvider(OAuthProvider):
def is_enabled(self) -> bool: def is_enabled(self) -> bool:
return bool(self.client_id and self.client_secret) 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 ( params = {
f"{self.base}/login/oauth/authorize?" "client_id": self.client_id,
+ urlencode({ "redirect_uri": redirect_uri or self.redirect_uri,
"client_id": self.client_id, "response_type": "code",
"redirect_uri": redirect_uri or self.redirect_uri, "state": state,
"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: async def exchange_code(self, code: str, redirect_uri: str | None = None) -> dict | None:
url = f"{self.base}/login/oauth/access_token" url = f"{self.base}/login/oauth/access_token"
@@ -143,7 +146,7 @@ class GitHubProvider(OAuthProvider):
def is_enabled(self) -> bool: def is_enabled(self) -> bool:
return bool(self.client_id and self.client_secret) 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 ( return (
f"{self.authorize_url}?" f"{self.authorize_url}?"
+ urlencode({ + urlencode({
+1 -1
View File
@@ -121,7 +121,7 @@ async def login(request: Request, provider: str = Query("gitea")):
# Dynamic redirect URI based on incoming Host header # Dynamic redirect URI based on incoming Host header
host = request.headers.get("host", "localhost:8080") host = request.headers.get("host", "localhost:8080")
dynamic_redirect_uri = f"http://{host}/auth/callback" 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) return RedirectResponse(url=auth_url, status_code=302)