From bb35e57ba4e07a96af98624aaa6e4a9aafba7089 Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Thu, 2 Oct 2025 15:57:20 -0600 Subject: [PATCH] Fix reset link logic to include /auth when no configured auth-host. --- passkey/bootstrap.py | 3 +-- passkey/fastapi/admin.py | 5 +++-- passkey/fastapi/api.py | 5 +++-- passkey/fastapi/reset.py | 3 +-- passkey/util/hostutil.py | 29 +++++++++++++++++------------ 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/passkey/bootstrap.py b/passkey/bootstrap.py index 9734a87..d0c08a1 100644 --- a/passkey/bootstrap.py +++ b/passkey/bootstrap.py @@ -47,8 +47,7 @@ async def _create_and_log_admin_reset_link(user_uuid, message, session_type) -> expires=authsession.expires(), info={"type": session_type}, ) - base = hostutil.auth_site_base_url() - reset_link = f"{base}{token}" + reset_link = hostutil.reset_link_url(token) logger.info(ADMIN_RESET_MESSAGE, message, reset_link) return reset_link diff --git a/passkey/fastapi/admin.py b/passkey/fastapi/admin.py index 9360ec5..5d6817c 100644 --- a/passkey/fastapi/admin.py +++ b/passkey/fastapi/admin.py @@ -357,8 +357,9 @@ async def admin_create_user_registration_link( expires=expires(), info={"type": "device addition", "created_by_admin": True}, ) - base = hostutil.auth_site_base_url(request.url.scheme, request.headers.get("host")) - url = f"{base}{token}" + url = hostutil.reset_link_url( + token, request.url.scheme, request.headers.get("host") + ) return {"url": url, "expires": expires().isoformat()} diff --git a/passkey/fastapi/api.py b/passkey/fastapi/api.py index 7f6f11a..b0af8b0 100644 --- a/passkey/fastapi/api.py +++ b/passkey/fastapi/api.py @@ -274,8 +274,9 @@ async def api_create_link(request: Request, auth=Cookie(None)): expires=expires(), info=session.infodict(request, "device addition"), ) - base = hostutil.auth_site_base_url(request.url.scheme, request.headers.get("host")) - url = f"{base}{token}" + url = hostutil.reset_link_url( + token, request.url.scheme, request.headers.get("host") + ) return { "message": "Registration link generated successfully", "url": url, diff --git a/passkey/fastapi/reset.py b/passkey/fastapi/reset.py index 60f95d6..05bc675 100644 --- a/passkey/fastapi/reset.py +++ b/passkey/fastapi/reset.py @@ -69,8 +69,7 @@ async def _create_reset(user, role_name: str): expires=_authsession.expires(), info={"type": "manual reset", "role": role_name}, ) - base = hostutil.auth_site_base_url() - return f"{base}{token}", token + return hostutil.reset_link_url(token), token async def _main(query: str | None) -> int: diff --git a/passkey/util/hostutil.py b/passkey/util/hostutil.py index 126815a..2493638 100644 --- a/passkey/util/hostutil.py +++ b/passkey/util/hostutil.py @@ -42,25 +42,30 @@ def ui_base_path() -> str: return "/" if is_root_mode() else "/auth/" -def _format_base_url(scheme: str, netloc: str) -> str: - scheme_part = scheme or _default_origin_scheme() - base = f"{scheme_part}://{netloc}" - return base if base.endswith("/") else f"{base}/" - - def auth_site_base_url(scheme: str | None = None, host: str | None = None) -> str: cfg = _load_config() if cfg: cfg_scheme, cfg_host = cfg scheme_to_use = cfg_scheme or scheme or _default_origin_scheme() - return _format_base_url(scheme_to_use, cfg_host) + netloc = cfg_host + else: + if host: + scheme_to_use = scheme or _default_origin_scheme() + netloc = host.strip("/") + else: + origin = global_passkey.instance.origin.rstrip("/") + return f"{origin}{ui_base_path()}" - if host: - scheme_to_use = scheme or _default_origin_scheme() - return _format_base_url(scheme_to_use, host.strip("/")) + base = f"{scheme_to_use}://{netloc}".rstrip("/") + path = ui_base_path().lstrip("/") + return f"{base}/{path}" if path else f"{base}/" - origin = global_passkey.instance.origin.rstrip("/") - return f"{origin}/auth/" + +def reset_link_url( + token: str, scheme: str | None = None, host: str | None = None +) -> str: + base = auth_site_base_url(scheme, host) + return f"{base}{token}" def reload_config() -> None: