Skip to main content
External OpenID Connect (OIDC) lets each team member authenticate to a GPU cluster’s Kubernetes API using their own identity from your organization’s identity provider (IdP), such as Google, Okta, Auth0, or Microsoft Entra ID. Access is then controlled with standard Kubernetes role-based access control (RBAC).
Use OIDC when you want per-user audit trails, per-user revocation, and least-privilege access via RBAC. You may not need this if you’re the only operator or you never interact with the Kubernetes API directly.

How it works

Kubernetes’ API server can validate JSON Web Tokens (JWTs) issued by an external OIDC provider. When a user runs kubectl, the OIDC kubeconfig calls a local helper that handles login interactively, then attaches the resulting token to every API request.
The flow has four stages: login, token, validate, and authorize.
1

Login

The user runs a kubectl command. kubectl sees the exec plugin in the OIDC kubeconfig and invokes kubectl-together_login. The plugin opens the user’s default browser and redirects to the IdP’s authorization endpoint with a PKCE challenge. The user signs in to the IdP with their organization credentials.
2

Token

The IdP issues a signed ID token (a JWT) and redirects back to http://localhost:8000 or :18000, where the plugin is listening. The plugin caches the token under $HOME/.kube/cache/oidc-login/ and returns it to kubectl.
3

Validate

kubectl sends the API request with the token in the Authorization: Bearer … header. The Kubernetes API server validates the token by fetching the IdP’s public signing keys from its OIDC discovery document (<issuer_url>/.well-known/openid-configuration), verifying the token’s signature, and checking that the iss and aud claims match the issuer URL and client ID configured on the cluster. A failure here returns 401 Unauthorized.
4

Authorize

The API server reads the configured username claim (email, preferred_username, or sub) and uses it as the user identity for RBAC. It evaluates ClusterRoleBindings and RoleBindings to decide whether the request is allowed. No matching binding returns 403 Forbidden.

Username claim

The username claim is the field in the OIDC token that Kubernetes uses as the identity for RBAC. The supported claims are email, preferred_username, and sub. Choose one that your IdP reliably provides. The claim sets the format of the identity, which is the exact value you pass as --user when you create RBAC bindings:
  • email produces [email protected], used as-is.
  • sub produces <issuer_url>#<sub_value>, for example https://accounts.google.com#105010678054620911233.
  • preferred_username produces <issuer_url>#<username>, for example https://login.microsoftonline.com/<TENANT_ID>/v2.0#[email protected].
The email claim gives the simplest RBAC setup, because its value needs no issuer prefix.

Requirements

To set up OIDC authentication, you need:
  • An OIDC-compatible identity provider, such as Google, Okta, Auth0, or Entra ID.
  • A GPU cluster with external OIDC enabled. You can enable OIDC only when you create the cluster.
  • kubectl installed locally.
  • The cluster’s admin kubeconfig, which the admin uses to create RBAC bindings. Only project admins can download it.

Set up the cluster (admin)

Complete these tasks as a project admin. When you’re done, share this page with your team members so they can connect to the cluster.
1

Create an OIDC application in your identity provider

Create an OIDC client or application in your identity provider with these settings:
  • Redirect URIs: http://localhost:8000 and http://localhost:18000.
  • Auth method: Authorization code flow with Proof Key for Code Exchange (PKCE).
  • Scopes: Always include openid. Add email if your username claim is email, or profile if it’s preferred_username. The sub claim needs no additional scopes.
The generated OIDC kubeconfig requests the scopes for your username claim through --oidc-extra-scope, so your IdP application only needs to allow them.Record the application’s Issuer URL and Client ID, which you enter when you enable OIDC on the cluster. If your provider requires a client secret, record the Client Secret too. Team members set it on their own machines, as described in Set the OIDC client secret.
Issuer URL formats by provider:
  • Auth0: The issuer URL must end with a trailing slash, for example https://your-tenant.auth0.com/. Without it, OIDC discovery fails.
  • Okta: Use the full authorization server URL, including /oauth2/default, for example https://your-org.okta.com/oauth2/default. The bare Okta domain returns invalid_client.
  • Google: The issuer URL is always https://accounts.google.com.
2

Enable external OIDC on the cluster

Configure OIDC when you create the cluster: You can’t add or change it after the cluster is created.
  1. Go to GPU Clusters → Create cluster, and set Orchestration to Kubernetes.
  2. Under Cluster add-ons, set Use custom OIDC to Yes. The OIDC fields below the toggle become editable.
  3. Optionally, select a Quick setup preset (Google, Okta, Auth0, or Entra ID) to prefill provider defaults.
  4. Enter the Issuer URL and Client ID from your OIDC application, and set Username Claim to email, preferred_username, or sub.
  5. Wait for Provider verification to check the discovery document, reachability, and required claims.
  6. Complete the rest of the form, then select Create Cluster and Confirm & Create.
3

Grant RBAC permissions

OIDC users have no access to the cluster until you create Kubernetes RBAC bindings for their identities. Create the bindings with the admin kubeconfig, not the OIDC kubeconfig, because OIDC users can’t grant themselves permissions.The console doesn’t configure a groups claim, so bind each user individually. To bind groups instead, you need oidc_config.group_claim, which you can set only when you create the cluster through the API or SDK.Set --user to the exact identity Kubernetes extracts from the token. Its format depends on your username claim:

Connect to the cluster (user)

Each team member completes these tasks on their local machine.
1

Download the OIDC kubeconfig

Only project admins can see the OIDC kubeconfig in the console. The file contains no credentials, so a project admin can share it with editors. If you’re a project editor, ask a project admin for the file and save it to $HOME/.kube/my-cluster-oidc.yaml.If you’re a project admin, download it once the cluster’s status is Ready:
  1. Open the cluster details page.
  2. In the sidebar, find OIDC Kubeconfig and select View.
  3. Copy the kubeconfig content and save it to $HOME/.kube/my-cluster-oidc.yaml:
On Linux, replace pbpaste with xclip -selection clipboard -o. On any platform, you can also paste the content into the file with a text editor, or select Download instead of View and save the downloaded file to the same path.
2

Install the login helper

The OIDC kubeconfig calls an exec plugin that handles browser-based login and token caching. Which plugin you install depends on what the OIDC Kubeconfig dialog’s Quick setup shows. If you’re a project editor, ask the project admin who shared your kubeconfig.If it shows kubelogin, your cluster is a Together-managed OIDC cluster, and its kubeconfig calls kubectl oidc-login. Install int128/kubelogin with brew install kubelogin or kubectl krew install oidc-login.If it shows together-login, download the binary for your platform from the together-kubelogin releases, verify its checksum, and move it onto your PATH:
Verify the installation:
3

Set the OIDC client secret

The kubeconfig uses PKCE (S256) by default, so most providers don’t require a client secret, and you can skip this task. Some providers, such as Google, require one even for desktop or native PKCE flows. If yours does, get the secret from your admin and set it for the current session:
Don’t store the secret in shell config files such as .bashrc or .zshrc: Set it per session, or inject it with a secrets manager.
4

Verify access

Test your access with the OIDC kubeconfig:
A browser opens for login. Sign in with your IdP credentials, then check the result:
  • Success: The command lists the cluster’s nodes. You’re authenticated and authorized.
  • 403 Forbidden: Authentication worked, but no RBAC binding exists for your identity. Ask your admin to complete Grant RBAC permissions.
On Together-managed OIDC clusters, RBAC is namespace-scoped, so get nodes returns 403 even when you have access. Verify with get pods instead.

Revoking access

To revoke a user’s access:
  1. Remove their RBAC binding from the cluster:
  2. Remove the user from your IdP, or from the relevant group, to prevent new tokens from being issued.
Existing tokens will continue to work until they expire. For immediate revocation, perform both steps together.

Token lifetime and refresh

OIDC tokens are short-lived (typically one hour, depending on your IdP configuration). When a token expires, the login plugin opens a browser automatically so you can sign in again. If your IdP supports refresh tokens, the plugin can renew the token without a login prompt. The plugin caches tokens locally in $HOME/.kube/cache/oidc-login/. To force a fresh login, clear the cache:
On Together-managed OIDC clusters, which use kubelogin, run kubectl oidc-login clean instead. Deleting the cache directory works with either plugin:
After a role or permissions change, clear the OIDC token cache: When your role changes, for example through new RBAC bindings or a change to your IdP group, the cached token may still carry the old identity or claims until it expires. Once you clear the cache, the next kubectl call starts a fresh login that picks up the new access.

Troubleshooting

403 Forbidden

Authentication succeeded, but no RBAC binding grants your identity the required permissions.
On Together-managed OIDC clusters, verify with get pods: If the OIDC Kubeconfig dialog’s Quick setup shows kubelogin rather than together-login, your cluster grants namespace-scoped RBAC, and get nodes returns 403 Forbidden even when authentication works. Run get pods instead:
Fix:

401 Unauthorized or “provide credentials”

Token validation failed at the API server. Fix:
  • Check the cluster’s OIDC configuration against the token. The issuer URL must match the token’s iss claim, the client ID must match its aud claim, and the token must contain the username claim.
  • Clear cached tokens and retry:

client_secret is missing

Your IdP requires a client secret that wasn’t provided. Fix:

Browser login doesn’t open

Fix:
  • Ensure kubectl-together_login is installed and on your PATH.
  • Run kubectl together-login --help to verify.

Security best practices

  • Use short-lived OIDC tokens, and rely on your IdP for user lifecycle (joiners, movers, leavers).
  • Keep the admin kubeconfig restricted to break-glass scenarios. Use OIDC for day-to-day access.
  • Use email as the username claim for the simplest RBAC setup. Other claims require issuer-prefixed --user values.