juanfont/headscale · warning · HTTPError
ErrSSHAuthSessionNotBound
ErrSSHAuthSessionNotBound
Error message
auth session is not for SSH check
What it means
Returned when the cached auth entry referenced by auth_id exists but is not an SSH check session (IsSSHCheck() false). The auth cache is shared by registration and SSH check flows; this guard ensures a follow-up URL only consumes sessions of the right kind, preventing cross-flow confusion.
Source
Thrown at hscontrol/noise.go:625
)
}
return nil, NewHTTPError(
http.StatusBadRequest,
"Invalid auth_id",
fmt.Errorf("%w: %s", ErrNoAuthSession, authID),
)
}
// Verify the cached binding matches the (src, dst) pair the
// follow-up URL claims. Without this check an attacker who knew an
// auth_id could submit a follow-up for any other (src, dst) pair
// and have its verdict recorded against that pair instead.
if !auth.IsSSHCheck() {
return nil, NewHTTPError(
http.StatusBadRequest,
"auth session is not for SSH check",
fmt.Errorf("%w: %s", ErrSSHAuthSessionNotBound, authID),
)
}
binding := auth.SSHCheckBinding()
if binding.SrcNodeID != srcNodeID || binding.DstNodeID != dstNodeID {
return nil, NewHTTPError(
http.StatusUnauthorized,
"src/dst pair does not match auth session",
fmt.Errorf(
"%w: cached %d->%d, request %d->%d",
ErrSSHBindingMismatch,
binding.SrcNodeID, binding.DstNodeID,
srcNodeID, dstNodeID,
),
)
}
reqLog.Trace().Caller().Msg("SSH action follow-up")View on GitHub (pinned to 565fd254d0)
Solutions
- Confirm the auth_id in the URL is the one issued for this SSH check, not a registration auth_id
- Restart the SSH session to obtain a fresh, correctly-bound auth_id
- If writing clients, keep auth IDs strictly scoped to the flow that created them
Defensive patterns
Strategy: type-guard
Type guard
func isSSHCheckSession(a types.AuthRequest) bool {
return a.IsSSHCheck()
} Prevention
- Scope every auth_id to the single flow that issued it
- On this error, always restart the SSH session rather than reusing the auth_id
When it happens
Trigger: Using an auth_id issued for a different purpose (e.g. node registration) against the /machine/ssh/action follow-up endpoint.
Common situations: Client bugs mixing up auth IDs between flows; manual experimentation with URLs; extremely unlikely organically since IDs are random and single-purpose.
Related errors
- Invalid auth_id
- ssh action: cached auth session is not an SSH-check binding
- ssh action: cached binding does not match request src/dst
- tags in SSH source cannot access user-owned devices
- user destination requires source to contain only that same u
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/870b8cee1b71e50d.
Report an issue: GitHub.