Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.together.ai/llms.txt

Use this file to discover all available pages before exploring further.

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. Supported values are email, preferred_username, or sub. Choose based on what your IdP reliably provides; email gives the simplest RBAC experience because the --user value is just the user’s email address.
The username claim affects the RBAC --user value. The format Kubernetes uses for the identity depends on which claim you choose:
  • email produces [email protected], used as-is.
  • sub produces <issuer-url>#<sub-value> (e.g., https://accounts.google.com#105010678054620911233).
  • preferred_username produces <issuer-url>#<username> (e.g., https://login.microsoftonline.com/<TENANT_ID>/v2.0#[email protected]).
You’ll need this exact value when creating RBAC bindings.

Prerequisites

Before you can set up OIDC authentication, make sure you have:

Set up the cluster (admin)

The tasks in this section are run by a cluster admin using the admin kubeconfig. Once these are complete, 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 the following settings.Redirect URIs:
  • http://localhost:8000.
  • http://localhost:18000.
Auth method: authorization code flow with Proof Key for Code Exchange (PKCE).Scopes:
  • Always include openid.
  • If using email as the username claim, add the email scope.
  • If using preferred_username as the username claim, add the profile scope.
  • If using sub as the username claim, no additional scopes are needed.
The kubeconfig generator automatically includes the correct scopes via --oidc-extra-scope based on your chosen username claim. You only need to ensure your IdP application allows these scopes.
Record these values; you’ll need them when enabling OIDC on the cluster:
Provider-specific issuer URL notes:
  • Auth0: the issuer URL must end with a trailing slash (e.g., https://your-tenant.auth0.com/). Without it, OIDC discovery will fail.
  • Okta: use the full authorization server URL including /oauth2/default (e.g., https://your-org.okta.com/oauth2/default). The bare Okta domain will return invalid_client.
  • Google: the issuer URL is always https://accounts.google.com.
2

Enable external OIDC on the cluster

OIDC must be configured at cluster creation time. It cannot be added or changed after the cluster is created.
  1. Go to GPU Clusters → Create cluster.
  2. Enable Use custom OIDC.
  3. Select Configure OIDC.
  4. Fill in:
    • Issuer URL from the OIDC application.
    • Client ID from the OIDC application.
    • Username claim: choose email, preferred_username, or sub.
  5. Wait for the UI to verify your configuration (discovery document, reachability, required claims).
  6. Create the cluster.
3

Grant RBAC permissions

Use the admin kubeconfig for this task, not the OIDC kubeconfig. OIDC users cannot grant themselves permission. An existing cluster admin must create the RBAC bindings first.
Before any OIDC user can access the cluster, a cluster admin must create Kubernetes RBAC bindings that grant permissions to their identity.The --user value must match the exact identity Kubernetes extracts from the token. This depends on which username claim you configured.If username claim is email:
kubectl create clusterrolebinding my-user-admin \
  --clusterrole=cluster-admin \
  --user="[email protected]"
If username claim is sub:
# Format: <issuer-url>#<sub-value>
kubectl create clusterrolebinding my-user-admin \
  --clusterrole=cluster-admin \
  --user="https://accounts.google.com#105010678054620911233"
If username claim is preferred_username:
# Format: <issuer-url>#<preferred-username-value>
kubectl create clusterrolebinding my-user-admin \
  --clusterrole=cluster-admin \
  --user="https://login.microsoftonline.com/<TENANT_ID>/v2.0#[email protected]"

Connect to the cluster (user)

The tasks in this section are run by each team member using their local machine.
1

Download the OIDC kubeconfig

Once the cluster status is Ready (visible on the cluster details page; see GPU clusters management):
  1. Open the cluster details page.
  2. Select View OIDC kubeconfig.
  3. Copy the kubeconfig content and save it to a file on your machine:
# Create the .kube directory if it doesn't exist.
mkdir -p $HOME/.kube

# Reads the kubeconfig from your clipboard. Run this immediately after copying from the dashboard.
pbpaste > $HOME/.kube/my-cluster-oidc.yaml   # macOS
On Linux, replace pbpaste with xclip -selection clipboard -o. On any platform, you can also paste into the file using your editor of choice.
2

Install the login helper

The OIDC kubeconfig uses an exec plugin to handle browser-based login and token caching. Download the binary for your platform from the together-kubelogin releases, verify its checksum, and move it onto your PATH.
curl -fsSL -O https://github.com/togethercomputer/together-kubelogin/releases/latest/download/kubectl-together_login_darwin_arm64.zip
curl -fsSL -O https://github.com/togethercomputer/together-kubelogin/releases/latest/download/kubectl-together_login_darwin_arm64.zip.sha256
shasum -a 256 -c kubectl-together_login_darwin_arm64.zip.sha256
unzip kubectl-together_login_darwin_arm64.zip
sudo mv kubectl-together_login /usr/local/bin/
rm kubectl-together_login_darwin_arm64.zip kubectl-together_login_darwin_arm64.zip.sha256
Verify the installation by running:
kubectl together-login --help
3

Set the OIDC client secret

The kubeconfig uses PKCE (S256) by default, so most providers do not require a client secret. However, some providers (e.g., Google) require one even for desktop or native PKCE flows. If your provider does not require a client secret, skip this task.If your provider requires it, set it for the current session:
export OIDC_CLIENT_SECRET="<your-client-secret>"
Do not persist this secret in shell config files (e.g., .bashrc, .zshrc). Set it per session, or use a secrets manager to inject it.
4

Verify access

Run:
# Clear any cached tokens from previous attempts.
rm -rf $HOME/.kube/cache/oidc-login/

# Test access using the OIDC kubeconfig.
kubectl --kubeconfig=$HOME/.kube/my-cluster-oidc.yaml get nodes
What to expect:
  • Browser opens for login. Sign in with your IdP credentials.
  • 403 Forbidden: authentication worked, but no RBAC binding exists for your identity. Ask your admin to complete Grant RBAC permissions.
  • Success: you’re authenticated and authorized. You’re done.

Revoking access

To revoke a user’s access:
  1. Remove their RBAC binding from the cluster:
    kubectl delete clusterrolebinding my-user-admin
    
  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 automatically opens a browser for re-authentication. If your IdP supports refresh tokens, re-authentication may be seamless without a login prompt. Cached tokens are stored locally in $HOME/.kube/cache/oidc-login/. To force a fresh login, delete this directory.

Troubleshooting

403 Forbidden

Authentication succeeded, but there is no RBAC binding granting that identity the required permissions. Fix:
  • Confirm the exact value of your username claim (e.g., is it [email protected] or a sub UUID?).
  • Ask a cluster admin to create a ClusterRoleBinding or RoleBinding for your user or group (see Grant RBAC permissions).

401 Unauthorized or “provide credentials”

Token validation failed at the API server. Fix:
  • Verify the cluster’s OIDC configuration: issuer URL must match token iss, client ID must match token aud, and the username claim must exist in the token.
  • Clear cached tokens and retry:
    rm -rf $HOME/.kube/cache/oidc-login/
    

client_secret is missing

Your IdP requires a client secret that wasn’t provided. Fix:
export OIDC_CLIENT_SECRET="<your-client-secret>"

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.