#17634·jumpserver

[Bug] v5.0.0 Web terminal SSH sessions are disconnected with "Access permission expired" – one-time connection token is expired on use but re-validated during the session

Author: andr3jkCreated Sep 29, 2026Updated Sep 29, 2026
Labels🐛 Bug🔔 Pending processing

Product Version

v5.0.0

Product Edition

  • Community Edition
  • Enterprise Edition
  • Enterprise Trial Edition

Installation Method

  • Online Installation (One-click command installation)
  • Offline Package Installation
  • All-in-One
  • 1Panel
  • Kubernetes
  • Source Code

Environment Information

OS: Debian13, Docker: 29.8.1, single host, all components in Docker (jms_core, jms_koko, jms_web, ...)

Bug Description

When connecting to an SSH asset via the Web Terminal, the session works normally, but after a short time the browser shows several warnings:

Permission expired: Connection Token Expired: 2026-09-29 09:50:18.268838+02:00

After ~4 warnings KoKo terminates the session:

Permission has expired, disconnect
Koko ended the session: Access permission expired

The asset permission and the user are NOT expired. Server time is NTP-synchronized; host, core and koko containers have identical time and TZ.

The database shows that every one-time connection token is expired ~0.2 s after creation:

select date_created, date_expired, date_expired - date_created as validity, is_reusable, protocol, account
from authentication_connectiontoken order by date_created desc limit 5;

 date_created                  | date_expired                  | validity        | is_reusable | protocol | account
 2026-09-29 16:06:27.167795+08 | 2026-09-29 16:06:27.406117+08 | 00:00:00.238322 | f           | ssh      | @INPUT
 2026-09-29 15:50:18.08012+08  | 2026-09-29 15:50:18.268838+08 | 00:00:00.188718 | f           | ssh      | @INPUT
 2026-09-29 15:49:59.75259+08  | 2026-09-29 15:49:59.970414+08 | 00:00:00.217824 | f           | ssh      | @INPUT

The date_expired of the token matches exactly the timestamp in the "Connection Token Expired" warning.

Analysis

  1. apps/authentication/api/connection_token.py – the secret action calls token.expire() when KoKo consumes the token (unless reusable, expire_now=false, or asset type is k8s/kubernetes).
  2. During the session KoKo periodically re-validates the token; this ends in ConnectionToken.is_valid() (apps/authentication/models/connection_token.py), which raises Connection token expired at: {} because is_expired is now true.
  3. The renewal action also rejects already-expired tokens, so the token cannot be renewed either.

So the periodic in-session check uses the same validation as the initial connection. For a running session it should check the asset permission (expire_at / permed_account.date_expired), not whether the intentionally consumed one-time token is still valid. There is already an exception for k8s (expire_now = False), but not for SSH/SFTP/Telnet.

Recurrence Steps

  1. Web Terminal → connect to any SSH asset (manual input account @INPUT, not tested with saved accounts yet)
  2. Work normally in the session
  3. After a short time "Connection Token Expired" warnings appear, then the session is terminated with "Access permission expired"

Expected Behavior

An active session should stay connected as long as the user's asset permission is valid. Consuming the one-time token at connect time should not terminate the running session.

Attempted Solutions

Workaround (temporary): extend the k8s exception to SSH/SFTP/Telnet in api/connection_token.py:

if asset_type in ['k8s', 'kubernetes'] or token.protocol in ('ssh', 'sftp', 'telnet'):
    expire_now = False

plus CONNECTION_TOKEN_ONETIME_EXPIRATION=28800 in config.txt. With this the sessions stay connected, but the one-time token remains valid until its natural expiry, which weakens the one-time semantics.

Suggested Fix

The workaround above weakens the one-time token semantics, so it should not be the final fix. Possible proper fixes (we did not inspect the KoKo side, so the exact endpoint used for the periodic check may differ):

  1. Separate the in-session check from the connect-time validation. For the periodic permission check of an already running session, do not reject the token because is_expired is true after consumption. Instead validate what actually matters for a running session: user is valid, asset is active, and the asset permission is still valid (expire_at / permed_account.date_expired).
  2. Alternatively, allow renewal for tokens that belong to an active session, so KoKo can keep the session alive without the token being reusable for new connections.
  3. As a stop-gap, the existing k8s exception (expire_now = False) could be extended to long-lived protocols (ssh/sftp/telnet), but together with a short CONNECTION_TOKEN_ONETIME_EXPIRATION this only moves the disconnect to the token's natural expiry.

Option 1 keeps the one-time token protection for new connections and fixes the disconnects of running sessions.

Expected Behavior

No response

Additional Information

No response

Attempted Solutions

No response