Skip to content

feat: supports one-time-token login and logout from webui#8589

Open
Soulter wants to merge 2 commits into
masterfrom
feat/one-time-token-login
Open

feat: supports one-time-token login and logout from webui#8589
Soulter wants to merge 2 commits into
masterfrom
feat/one-time-token-login

Conversation

@Soulter
Copy link
Copy Markdown
Member

@Soulter Soulter commented Jun 5, 2026

Modifications / 改动点

  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果


Checklist / 检查清单

  • 😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
    / 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。

  • 👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
    / 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”

  • 🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
    / 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到 requirements.txtpyproject.toml 文件相应位置。

  • 😮 My changes do not introduce malicious code.
    / 我的更改没有引入恶意代码。

Summary by Sourcery

Add support for logging into the dashboard with a one-time temporary token alongside existing username/password and TOTP flows.

New Features:

  • Introduce a temporary-token based login flow in the dashboard UI, including a dedicated login stage and toggle based on backend setup status.
  • Add backend support for temporary-token login, issuing short-lived JWTs and exposing temporary-login availability via the auth setup-status API.
  • Generate and optionally print a process-scoped temporary dashboard login token via a new CLI flag and propagate it into the core lifecycle for verification.
  • Add a logout entry to the dashboard header menu and corresponding icon support.

Enhancements:

  • Refactor dashboard auth routes to share JWT generation and cookie-setting logic with configurable max-age for different login types.
  • Improve startup credentials logging to include either an initial password, a temporary login token, or both, with clear guidance.

Documentation:

  • Extend the Chinese FAQ to document dashboard login security options, rate limiting, proxy header handling, and the temporary-token login behavior.

Tests:

  • Add integration tests covering temporary-token login, including invalid token handling, JWT expiry, and access to protected endpoints.

@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. area:webui The bug / feature is about webui(dashboard) of astrbot. labels Jun 5, 2026
@Soulter Soulter changed the title feat: supports one-time-token login feat: supports one-time-token login and logout feature Jun 5, 2026
@Soulter Soulter changed the title feat: supports one-time-token login and logout feature feat: supports one-time-token login and logout from webui Jun 5, 2026
@Soulter Soulter requested a review from Raven95676 June 5, 2026 04:07
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • Instead of using // @ts-ignore in syncReturnUrl, consider defining returnUrl with a proper type on the auth store so the component can assign to it without suppressing type checking.
  • The error-handling behavior for login and loginWithTemporaryToken differs (custom validateStatus vs default Axios behavior), which may lead to inconsistent error messages at the UI layer; it would be cleaner to align their status validation and error shaping.
  • The /api/auth/setup-status call is made directly from AuthLogin.vue; consider moving this into a store or shared composable so that login-related API concerns remain centralized and easier to reuse.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Instead of using `// @ts-ignore` in `syncReturnUrl`, consider defining `returnUrl` with a proper type on the auth store so the component can assign to it without suppressing type checking.
- The error-handling behavior for `login` and `loginWithTemporaryToken` differs (custom `validateStatus` vs default Axios behavior), which may lead to inconsistent error messages at the UI layer; it would be cleaner to align their status validation and error shaping.
- The `/api/auth/setup-status` call is made directly from `AuthLogin.vue`; consider moving this into a store or shared composable so that login-related API concerns remain centralized and easier to reuse.

## Individual Comments

### Comment 1
<location path="dashboard/src/stores/auth.ts" line_range="83-74" />
<code_context>
+        return Promise.reject(error);
+      }
+    },
+    async loginWithTemporaryToken(token: string): Promise<void> {
+      try {
+        const res = await axios.post("/api/auth/login", {
+          login_type: "temporary_token",
+          temporary_token: token,
+        });
+
+        if (res.data.status === "error") {
           return Promise.reject(res.data.message);
         }
</code_context>
<issue_to_address>
**issue (bug_risk):** Align temporary token login error handling with password login to surface API error messages reliably.

Because `loginWithTemporaryToken` relies on Axios’ default `validateStatus`, 4xx responses (like the 401 for invalid tokens) throw before you can read `res.data`, so the UI only sees a generic AxiosError instead of the backend message.

To match the main `login` behavior and surface the server error string, either:
- Override `validateStatus` so 401 responses pass through and you can `Promise.reject(res.data.message)`, or
- In `catch`, map `error.response.data.message` to the rejected error.

This keeps temporary token failures consistent with regular login errors from a UX standpoint.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

return "totp_required";
}

if (res.data.status === "error") {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Align temporary token login error handling with password login to surface API error messages reliably.

Because loginWithTemporaryToken relies on Axios’ default validateStatus, 4xx responses (like the 401 for invalid tokens) throw before you can read res.data, so the UI only sees a generic AxiosError instead of the backend message.

To match the main login behavior and surface the server error string, either:

  • Override validateStatus so 401 responses pass through and you can Promise.reject(res.data.message), or
  • In catch, map error.response.data.message to the rejected error.

This keeps temporary token failures consistent with regular login errors from a UX standpoint.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a temporary login token feature for the AstrBot dashboard, allowing users to log in using a token printed in the startup logs (enabled via the --print-login-token CLI flag). This includes backend support for hashing, verifying, and issuing shorter-lived JWTs for temporary token sessions, as well as frontend UI updates to support the temporary token login flow, translation updates, and documentation. A review comment points out a usability issue where users logged in via a temporary token cannot reset their password because the account edit endpoint still requires verifying the original password. It is recommended to add a claim to the JWT indicating a temporary session and bypass the original password check in this scenario.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +248 to +253
return await self._create_login_response(
username,
storage_upgraded,
password,
jwt_max_age=DASHBOARD_TEMPORARY_LOGIN_JWT_MAX_AGE,
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

⚠️ Password Reset Usability Trap when Logged in via Temporary Token

When a user logs in using a temporary token (typically to recover access after forgetting their password), they are issued a standard JWT. However, if they attempt to reset or update their password via the WebUI (which calls the /api/auth/account/edit endpoint), the request will fail because edit_account strictly requires the original password to be verified:

if not verify_dashboard_password(password, req_password):
    return Response().error("原密码错误").__dict__

Since the user logged in via the temporary token precisely because they do not know or want to bypass the original password, they are trapped and cannot set a new password through the UI.

Suggested Solution:

  1. Add an is_temporary: bool = False claim to the JWT payload when generated via temporary token login.
  2. Propagate this claim to g.is_temporary in the authentication middleware (server.py).
  3. In edit_account, bypass the original password verification if getattr(g, "is_temporary", False) is True.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:webui The bug / feature is about webui(dashboard) of astrbot. size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant