feat: add Gitea OAuth2 redirect and callback routes

This commit is contained in:
2026-05-08 13:44:12 -04:00
parent d190029728
commit 76edfe7577
+44
View File
@@ -16,6 +16,7 @@ from . import data
from . import notify as notify_mod from . import notify as notify_mod
from . import settings as settings_mod from . import settings as settings_mod
from . import users as users_mod from . import users as users_mod
from . import oauth as oauth_mod
from . import ws as ws_mod from . import ws as ws_mod
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -897,6 +898,47 @@ async def start(
) )
return web.Response(text=body, content_type="text/html") return web.Response(text=body, content_type="text/html")
async def oauth_gitea_redirect(request):
"""GET /login/oauth/gitea — kick off the Gitea OAuth2 flow."""
if not oauth_mod.is_enabled(config):
return web.Response(status=404, text="OAuth not configured")
state = oauth_mod.make_state()
redirect_uri = f"{request.url.origin()}/login/oauth/gitea/callback"
raise web.HTTPFound(oauth_mod.authorization_url(config, state, redirect_uri))
async def oauth_gitea_callback(request):
"""GET /login/oauth/gitea/callback — handle Gitea's redirect back."""
if not oauth_mod.is_enabled(config):
return web.Response(status=404, text="OAuth not configured")
code = request.rel_url.query.get("code", "")
state = request.rel_url.query.get("state", "")
if not code or not state:
return web.Response(status=400, text="Missing code or state")
if not oauth_mod.validate_state(state):
raise web.HTTPFound("/login?error=1")
redirect_uri = f"{request.url.origin()}/login/oauth/gitea/callback"
try:
token = await oauth_mod.exchange_code(config, code, redirect_uri)
profile = await oauth_mod.fetch_user(config, token)
except oauth_mod.OAuthError as exc:
logger.warning("OAuth error: %s", exc)
raise web.HTTPFound("/login?error=1")
user = users_mod.provision_oauth_user(
profile["login"],
profile["full_name"],
profile["avatar_url"],
)
session_token = users_mod.create_session(user.username)
resp = web.HTTPFound("/")
resp.set_cookie(
SESSION_COOKIE,
session_token,
max_age=users_mod.SESSION_TTL,
httponly=True,
samesite="Lax",
)
raise resp
app = web.Application() app = web.Application()
app.add_routes( app.add_routes(
[ [
@@ -908,6 +950,8 @@ async def start(
web.get("/logout", web_logout), web.get("/logout", web_logout),
web.post("/api/0/auth/login", api_login), web.post("/api/0/auth/login", api_login),
web.post("/api/0/auth/logout", api_logout), web.post("/api/0/auth/logout", api_logout),
web.get("/login/oauth/gitea", oauth_gitea_redirect),
web.get("/login/oauth/gitea/callback", oauth_gitea_callback),
# Users # Users
web.get("/api/0/users", api_users), web.get("/api/0/users", api_users),
web.get("/api/0/users/me", api_user_self), web.get("/api/0/users/me", api_user_self),