Skip to content

SSH Sessions

The SSH Sessions resource provides read-only access to the SSH session activity recorded by Keystash's SSH Connection Logging. Each session captures who connected to a Host Server, from where, how they authenticated and how long they stayed — the same activity you can browse in the app under SSH Sessions. Access to this resource requires the SSH Sessions → View Role permission (see Roles & Permissions).

Note

These endpoints are read-only — there is no create, update or delete.

List SSH Sessions

Returns the company's SSH sessions, newest first, with optional filtering and paging. With no parameters supplied you get the most recent sessions, up to the default limit.

Path: /ssh-sessions/list

Method: GET

Authentication: Bearer Token

Request Headers

Key Value Required
Accept-Encoding gzip optional

Request Parameters

All parameters are optional query parameters. Malformed filter values are silently dropped, so a bad value yields more results, not an error.

Key Data Type Required Notes
start_date string optional Inclusive lower bound on the session start, in UTC YYYY-MM-DD HH:mm:ss. Must be supplied together with end_date — a lone date is ignored.
end_date string optional Inclusive upper bound on the session start, in UTC YYYY-MM-DD HH:mm:ss. Together with start_date, filters on started_at between the two dates.
user_ids array of string optional Filter to sessions for these Keystash users, by their id — the user.id field in a response, and the id a Users API call returns. Each value must be 1–16 alphanumeric characters or the whole filter is dropped. See the array note below.
server_ids array of string optional Filter by server, by its id — the server.id field in a response. Each value must be 1–16 alphanumeric characters or the whole filter is dropped. See the array note below.
server_group_ids array of string optional Filter by Server Group, by its id — the server.server_group_id field in a response. Same array and id validation as server_ids.
statuses array of string optional Filter by session status label: Incomplete, Failed, Active or Ended (case-insensitive, surrounding whitespace trimmed). A single unrecognised label drops the whole filter. See the array note below.
limit integer optional Maximum number of rows to return. Defaults to 10000 and is limited to the range 110000.
offset integer optional Row offset for paging. Defaults to 0 and is limited to 0 or greater.

Note

The array filters — user_ids, server_ids, server_group_ids and statuses — must be sent as repeated, bracketed query parameters, for example ?statuses[]=Ended&statuses[]=Active or ?server_ids[]=DmcEgixUXpWVv7tk. A bare ?statuses=Ended arrives as a scalar string, fails the array check and is ignored — even for a single value. Always use the bracketed form, as shown in the example request.

Request Body

None.

Response Fields

A successful response is a JSON array of session objects. Each object has these fields:

Field Type Notes
id string The session's Keystash id. Pass this to View SSH Session as the id parameter.
session_id string The agent/PAM session identifier the host reported. Unique per session on a given server.
status string The session status label: Incomplete, Failed, Active or Ended (or Unknown if unmapped). This is the same label accepted by the statuses filter. See Session Statuses.
user object The resolved Keystash user. The user fields are null if the user could not be resolved or was later deleted.
user.id string|null The Keystash user id. null for unresolved or root logins. Use it in the user_ids filter.
user.name string|null The user's full name (firstname lastname).
user.email string|null The user's email / Keystash username.
user.server_username string|null The Linux username the session logged in as.
server object The target server.
server.id string|null The server id. Use it in the server_ids filter.
server.hostname string|null The server hostname.
server.server_group_id string|null The server's Server Group id. Use it in the server_group_ids filter.
server.server_group_name string|null The Server Group name.
ip_address string The source IP address the user connected from.
auth_method string|null The raw authentication-method token (see Authentication Methods). unknown when not reported.
auth_method_label string The human label for auth_method.
mfa_method string|null The raw MFA-method token (see MFA Methods).
mfa_method_label string The human label for mfa_method.
started_at string UTC timestamp of the first event — the session start.
connected_at string|null UTC timestamp of connect; null if the session never connected.
disconnected_at string|null UTC timestamp of disconnect; null while the session is still Active or never completed.
duration_seconds integer|null The connect-to-disconnect duration in seconds; null while the session is Active, Failed or Incomplete.
deny_reason string|null The raw deny-reason token; null unless the session was denied (see Deny Reasons).
deny_reason_label string The human label for deny_reason (empty string when none).

Note

An empty result is a 200 OK with an empty array ([]), the list simply returns no matches.

Example Request

curl --location --request GET 'https://app.keystash.io/api/v1/ssh-sessions/list?statuses[]=Ended&limit=50' \
--header 'Authorization: Bearer <token>'

Example Response

The example below shows one Ended session (with duration_seconds and disconnected_at populated) and one Active session (still connected, so those fields are null).

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

[
  {
    "id": "x0Uf09z3TYjoNVFv",
    "session_id": "sshd-8f3c1a2b9d4e",
    "status": "Ended",
    "user": {
      "id": "bkQV8I5BRcAVpg1d",
      "name": "Max Smith",
      "email": "max.smith@example.org",
      "server_username": "maxsmith"
    },
    "server": {
      "id": "DmcEgixUXpWVv7tk",
      "hostname": "web-01.hostingprovider.net",
      "server_group_id": "BD720EP87kNORRcH",
      "server_group_name": "Production Servers"
    },
    "ip_address": "192.168.1.58",
    "auth_method": "pubkey",
    "auth_method_label": "Public Key",
    "mfa_method": "totp_mfa",
    "mfa_method_label": "TOTP",
    "started_at": "2026-06-22 09:14:00",
    "connected_at": "2026-06-22 09:14:02",
    "disconnected_at": "2026-06-22 09:25:11",
    "duration_seconds": 669,
    "deny_reason": null,
    "deny_reason_label": ""
  },
  {
    "id": "p8CduXmyw6n9dzdd",
    "session_id": "sshd-1b7e44c0aa21",
    "status": "Active",
    "user": {
      "id": "tr568I5BRcAVpwx7",
      "name": "Anne Teak",
      "email": "anne.teak@example.org",
      "server_username": "anneteak"
    },
    "server": {
      "id": "DmcEgixUXpWVv7tk",
      "hostname": "web-01.hostingprovider.net",
      "server_group_id": "BD720EP87kNORRcH",
      "server_group_name": "Production Servers"
    },
    "ip_address": "192.168.1.59",
    "auth_method": "pubkey",
    "auth_method_label": "Public Key",
    "mfa_method": "none",
    "mfa_method_label": "None",
    "started_at": "2026-06-22 11:02:40",
    "connected_at": "2026-06-22 11:02:41",
    "disconnected_at": null,
    "duration_seconds": null,
    "deny_reason": null,
    "deny_reason_label": ""
  }
]

A Failed session looks like the object below — it never connected, so the connect, disconnect and duration fields are null, and the deny_reason/deny_reason_label pair explains why it was refused.

{
  "id": "H6LPlSC081GIqzW0",
  "session_id": "sshd-c92f0d7e6b15",
  "status": "Failed",
  "user": {
    "id": "bkQV8I5BRcAVpg1d",
    "name": "Max Smith",
    "email": "max.smith@example.org",
    "server_username": "maxsmith"
  },
  "server": {
    "id": "DmcEgixUXpWVv7tk",
    "hostname": "web-01.hostingprovider.net",
    "server_group_id": "BD720EP87kNORRcH",
    "server_group_name": "Production Servers"
  },
  "ip_address": "203.0.113.42",
  "auth_method": "password",
  "auth_method_label": "Password",
  "mfa_method": "totp_mfa",
  "mfa_method_label": "TOTP",
  "started_at": "2026-06-22 08:47:13",
  "connected_at": null,
  "disconnected_at": null,
  "duration_seconds": null,
  "deny_reason": "bad_code",
  "deny_reason_label": "Invalid 2FA code"
}

Example Error Response

Missing Permission (403 Forbidden)

HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8

{
  "error": {
    "code": "Forbidden",
    "message": "You do not have the required permission to access this path.",
    "details": [
      {
        "path": "/api/v1/ssh-sessions/list"
      }
    ]
  }
}

Database Error (500 Internal Server Error)

HTTP/1.1 500 Internal Server Error
Content-Type: application/json; charset=utf-8

{
  "error": {
    "code": "DataRetrievalError",
    "message": "There was a problem retrieving the data from the database.",
    "details": []
  }
}

View SSH Session

Returns a single session together with its ordered authentication-event timeline.

Path: /ssh-sessions/view

Method: GET

Authentication: Bearer Token

Request Headers

Key Value Required
Accept-Encoding gzip optional

Request Parameters

Key Data Type Required Notes
id string required The session id — the id field from a List SSH Sessions response. A missing or empty value returns 400 BadArgument; an unknown id returns 404 NotFound.

Request Body

None.

Response Fields

A successful response is a single object with two fields:

Field Type Notes
session object The session, with exactly the same fields as a List SSH Sessions entry.
events array of object The session's authentication events, oldest first.

Each object in events has these fields:

Field Type Notes
id string The agent-assigned unique id for this event.
created string UTC timestamp of when the event occurred, in YYYY-MM-DD HH:mm:ss second precision. Events are returned oldest first.
event_type string The raw event token: attempt, authenticate, connect, disconnect or deny (see Event Types).
auth_method string|null The raw authentication-method token for this event (see Authentication Methods).
auth_method_label string The human label for auth_method.
mfa_method string|null The raw MFA-method token for this event (see MFA Methods).
mfa_method_label string The human label for mfa_method.
reason string|null The raw deny/result reason token; populated on deny events (see Deny Reasons).
reason_label string The human label for reason.

Example Request

curl --location --request GET 'https://app.keystash.io/api/v1/ssh-sessions/view?id=x0Uf09z3TYjoNVFv' \
--header 'Authorization: Bearer <token>'

Example Response

A clean Ended session traces from first attempt through to disconnect:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "session": {
    "id": "x0Uf09z3TYjoNVFv",
    "session_id": "sshd-8f3c1a2b9d4e",
    "status": "Ended",
    "user": {
      "id": "bkQV8I5BRcAVpg1d",
      "name": "Max Smith",
      "email": "max.smith@example.org",
      "server_username": "maxsmith"
    },
    "server": {
      "id": "DmcEgixUXpWVv7tk",
      "hostname": "web-01.hostingprovider.net",
      "server_group_id": "BD720EP87kNORRcH",
      "server_group_name": "Production Servers"
    },
    "ip_address": "192.168.1.58",
    "auth_method": "pubkey",
    "auth_method_label": "Public Key",
    "mfa_method": "totp_mfa",
    "mfa_method_label": "TOTP",
    "started_at": "2026-06-22 09:14:00",
    "connected_at": "2026-06-22 09:14:02",
    "disconnected_at": "2026-06-22 09:25:11",
    "duration_seconds": 669,
    "deny_reason": null,
    "deny_reason_label": ""
  },
  "events": [
    {
      "id": "a1B2c3D4e5F6g7H8",
      "created": "2026-06-22 09:14:00",
      "event_type": "attempt",
      "auth_method": "pubkey",
      "auth_method_label": "Public Key",
      "mfa_method": "none",
      "mfa_method_label": "None",
      "reason": null,
      "reason_label": ""
    },
    {
      "id": "i9J0k1L2m3N4o5P6",
      "created": "2026-06-22 09:14:01",
      "event_type": "authenticate",
      "auth_method": "pubkey",
      "auth_method_label": "Public Key",
      "mfa_method": "totp_mfa",
      "mfa_method_label": "TOTP",
      "reason": null,
      "reason_label": ""
    },
    {
      "id": "q7R8s9T0u1V2w3X4",
      "created": "2026-06-22 09:14:02",
      "event_type": "connect",
      "auth_method": "pubkey",
      "auth_method_label": "Public Key",
      "mfa_method": "totp_mfa",
      "mfa_method_label": "TOTP",
      "reason": null,
      "reason_label": ""
    },
    {
      "id": "y5Z6a7B8c9D0e1F2",
      "created": "2026-06-22 09:25:11",
      "event_type": "disconnect",
      "auth_method": "pubkey",
      "auth_method_label": "Public Key",
      "mfa_method": "totp_mfa",
      "mfa_method_label": "TOTP",
      "reason": null,
      "reason_label": ""
    }
  ]
}

A Failed session ends on a deny event whose reason/reason_label records why it was refused:

{
  "session": {
    "id": "H6LPlSC081GIqzW0",
    "session_id": "sshd-c92f0d7e6b15",
    "status": "Failed",
    "user": {
      "id": "bkQV8I5BRcAVpg1d",
      "name": "Max Smith",
      "email": "max.smith@example.org",
      "server_username": "maxsmith"
    },
    "server": {
      "id": "DmcEgixUXpWVv7tk",
      "hostname": "web-01.hostingprovider.net",
      "server_group_id": "BD720EP87kNORRcH",
      "server_group_name": "Production Servers"
    },
    "ip_address": "203.0.113.42",
    "auth_method": "password",
    "auth_method_label": "Password",
    "mfa_method": "totp_mfa",
    "mfa_method_label": "TOTP",
    "started_at": "2026-06-22 08:47:13",
    "connected_at": null,
    "disconnected_at": null,
    "duration_seconds": null,
    "deny_reason": "bad_code",
    "deny_reason_label": "Invalid 2FA code"
  },
  "events": [
    {
      "id": "g3H4i5J6k7L8m9N0",
      "created": "2026-06-22 08:47:13",
      "event_type": "attempt",
      "auth_method": "password",
      "auth_method_label": "Password",
      "mfa_method": "none",
      "mfa_method_label": "None",
      "reason": null,
      "reason_label": ""
    },
    {
      "id": "o1P2q3R4s5T6u7V8",
      "created": "2026-06-22 08:47:15",
      "event_type": "deny",
      "auth_method": "password",
      "auth_method_label": "Password",
      "mfa_method": "totp_mfa",
      "mfa_method_label": "TOTP",
      "reason": "bad_code",
      "reason_label": "Invalid 2FA code"
    }
  ]
}

Example Error Response

Missing Session ID (400 Bad Request)

HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8

{
  "error": {
    "code": "BadArgument",
    "message": "A valid session id is required.",
    "details": []
  }
}

Session Not Found (404 Not Found)

HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8

{
  "error": {
    "code": "NotFound",
    "message": "Your request was successfully processed but there was no data to be returned.",
    "details": []
  }
}

Understanding the Values

Both endpoints use the same set of consistent labels for statuses, methods, events and deny reasons. The tables below explain what each one means. They mirror the labels shown in the app's SSH Sessions view.

Session Statuses

The status response field returns the label string, and the statuses filter accepts those same label strings (case-insensitive).

Label Meaning
Incomplete Only attempt or authenticate events were seen — the session never connected.
Failed A deny event occurred.
Active Connected, with no disconnect yet.
Ended A disconnect was received (or the session was swept after 72 hours stale-Active — see SSH Sessions).

Authentication Methods

These apply to the auth_method / auth_method_label fields.

Token Label
pubkey Public Key
password Password
keyboard-interactive Keyboard Interactive
gssapi GSSAPI
hostbased Host Based
unknown Not Reported

MFA Methods

These apply to the mfa_method / mfa_method_label fields.

Token Label
none None
totp_mfa TOTP
totp_mfa_scratch TOTP Scratch Code

Event Types

These apply to the events[].event_type field. The API emits the raw token only; the meanings are below.

Token Meaning
attempt An authentication attempt was made.
authenticate Authentication succeeded.
connect The session connected.
disconnect The session disconnected.
deny The session was denied (see reason).

Deny Reasons

These apply to the deny_reason / reason tokens and their *_label fields. Any token not listed below is humanised automatically — underscores become spaces and the result is title-cased.

Token Label
not_authorized Not authorized
unenrolled_denied Denied - User not enrolled in 2FA
not_enrolled Not enrolled in 2FA
bad_code Invalid 2FA code
rate_limited Rate limited
replay 2FA code already used
attempts_exhausted Too many failed attempts
mfa_method_unknown Unknown MFA method
agent_unavailable_deny Agent unavailable — denied
agent_unavailable_allow Agent unavailable — allowed