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 performs an OIDC
Authorization Code flow with PKCE:
--no-browser).~/.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 slug. 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/<slug>.json.
The tunnel edge validates each connection by checking three things, so a leaked token can't be used to hijack a slug:
- 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.
- Slug agreement — the slug in the signed token, the database row, and the client's requested proxy name 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.