Authentication & tokens
How the CLI authenticates with SSO, and the two kinds of tokens involved.
tunnelctl uses your organization's identity provider (OIDC, e.g. Keycloak) for authentication. There is no separate tunnelctl password — you sign in with SSO.
User authentication (OIDC)
When you run tunnelctl login, the CLI authenticates via OIDC —
Authorization Code + PKCE on a desktop, or the Device Authorization Grant
(RFC 8628) on headless environments; the default --auth-flow=auto picks the right one:
~/.config/tunnelctl/oidc.json with mode 0600.The access token is sent as Authorization: Bearer <token> to the control-plane API,
which validates its signature, issuer, audience, and expiry, and derives your permissions
from provider-specific claims.
Connection tokens
Authenticating you to the API is separate from authorizing an FRP client to serve a
specific endpoint. For that, the server issues a per-tunnel connection token (a signed
JWT) when you bring a tunnel up. The CLI stores it alongside the tunnel's metadata in
~/.config/tunnelctl/tunnels/<name>.json (<name> is the slug for HTTP, tcp-<port> /
udp-<port> for L4).
The tunnel edge validates each connection by checking three things, so a leaked token can't be used to hijack an endpoint:
- Signature — the token is signed by the server.
- Serial — the token's serial must match the tunnel's current serial; rotating the token bumps the serial and invalidates older ones.
- Endpoint agreement — the protocol and endpoint (HTTP slug, or TCP/UDP remote port) in the signed token, the database row, and the client's requested proxy must all match.
Rotation, not expiry
Connection tokens don't rely on short expiry — they're revoked by rotating the serial. Issuing a fresh token (e.g. via the server's rotate operation) immediately invalidates the previous one.
API keys (automation)
For non-interactive use, the server can issue scoped API keys (signed JWTs) to a caller that is already authenticated via OIDC. An API key can only carry a subset of the issuing user's permissions, so it can't be used to escalate privileges.