OIDC and Identity Provider Setup
This guide covers configuring user authentication for the Riptides control plane UI and API using OpenID Connect (OIDC) identity providers.
Overview
Section titled “Overview”Riptides uses OIDC to authenticate human users (platform engineers, security teams, operators) who access the control plane. The flow works as follows:
- A user navigates to the Riptides UI or runs a
kubectlcommand that requires authentication. - They are redirected to the configured identity provider (GitHub, Google, Bitbucket, or a static provider).
- After authenticating with the IdP, the user is redirected back with an OIDC token.
- Riptides validates the token and establishes a session.
You configure this with two Riptides custom resources:
- IdentityProvider: Defines the external IdP (GitHub, Google, etc.) and any restrictions (e.g., required organizations).
- OIDCClient: Defines an application that can initiate OIDC flows (the Riptides UI, kubectl, or your own applications).
Prerequisites
Section titled “Prerequisites”- A running Riptides control plane
kubectlaccess to theriptides-systemnamespace- OAuth app credentials from your identity provider (e.g., a GitHub OAuth App)
Step 1: Create an IdentityProvider
Section titled “Step 1: Create an IdentityProvider”GitHub
Section titled “GitHub”The most common setup uses GitHub as the identity provider, restricting access to members of specific organizations.
First, create a GitHub OAuth App:
- Go to your GitHub organization’s Settings > Developer settings > OAuth Apps > New OAuth App.
- Set the Authorization callback URL to
https://<your-controlplane-url>/oidc/auth/callback. - Note the Client ID and generate a Client Secret.
Then create the IdentityProvider resource:
apiVersion: core.riptides.io/v1alpha1kind: IdentityProvidermetadata: name: github namespace: riptides-systemspec: name: GitHub github: clientID: "<your-github-client-id>" clientSecret: "<your-github-client-secret>" requiredOrgs: - name: "<your-github-organization>"Field reference:
| Field | Description |
|---|---|
spec.name | Display name shown on the login screen. |
github.clientID | OAuth App client ID from GitHub. |
github.clientSecret | OAuth App client secret from GitHub. |
github.requiredOrgs | List of GitHub organizations. Only members of these organizations can authenticate. |
riptides-cli ctl apply -f identityprovider-github.yamlVerify the provider is ready:
riptides-cli ctl get identityprovider github -o jsonpath='{.status.state}'# AvailableIf it shows Failed, check the reason:
riptides-cli ctl get identityprovider github -o jsonpath='{.status.message}'apiVersion: core.riptides.io/v1alpha1kind: IdentityProvidermetadata: name: google namespace: riptides-systemspec: name: Google google: clientID: "<your-google-client-id>" clientSecret: "<your-google-client-secret>" requiredHostedDomains: - "<your-domain.com>"The requiredHostedDomains field restricts login to users with email addresses in the specified domain(s).
Bitbucket
Section titled “Bitbucket”apiVersion: core.riptides.io/v1alpha1kind: IdentityProvidermetadata: name: bitbucket namespace: riptides-systemspec: name: Bitbucket bitbucket: clientID: "<your-bitbucket-client-id>" clientSecret: "<your-bitbucket-client-secret>"Static (Development / Testing)
Section titled “Static (Development / Testing)”For development environments where you do not want to set up an external IdP, use the static provider with a single hardcoded user identity:
apiVersion: core.riptides.io/v1alpha1kind: IdentityProvidermetadata: name: static-dev namespace: riptides-systemspec: name: "Dev Login" static: email: "admin@example.com" name: "Dev Admin" preferredUsername: "admin" groups: - "platform"Warning: The static provider is intended for development and testing only. Do not use it in production.
Step 2: Create an OIDCClient
Section titled “Step 2: Create an OIDCClient”OIDCClients represent applications that initiate OIDC authentication flows. Riptides supports two types:
Native Client (kubectl and Riptides UI)
Section titled “Native Client (kubectl and Riptides UI)”A native client is used for the built-in Riptides UI and kubectl access. It uses PKCE (Proof Key for Code Exchange) and does not require a client secret.
apiVersion: core.riptides.io/v1alpha1kind: OIDCClientmetadata: name: riptides-ui namespace: riptides-systemspec: native: {} redirectUrls: - "https://<your-controlplane-url>/ui/callback" - "http://localhost:8000/auth/callback"The redirectUrls list includes:
- The production UI callback URL.
- A localhost callback for
kubectlauthentication flows (the CLI opens a local HTTP server to receive the callback).
riptides-cli ctl apply -f oidcclient-native.yamlCustom Client (External Applications)
Section titled “Custom Client (External Applications)”For integrating external applications (dashboards, CI/CD systems, custom tooling) with the Riptides control plane API, create a custom OIDCClient:
apiVersion: core.riptides.io/v1alpha1kind: OIDCClientmetadata: name: my-dashboard namespace: riptides-systemspec: custom: grantTypes: - authorization_code - refresh_token responseTypes: - code authMethod: client_secret_post redirectUrls: - "https://dashboard.example.com/callback"Field reference:
| Field | Description |
|---|---|
custom.grantTypes | OAuth 2.0 grant types the client can use. |
custom.responseTypes | OAuth 2.0 response types the client can use. |
custom.authMethod | How the client authenticates to the token endpoint (client_secret_post, client_secret_basic). |
redirectUrls | Allowed callback URLs after authentication. |
riptides-cli ctl apply -f oidcclient-custom.yamlAfter creation, Riptides generates a client ID and client secret for the custom client. Retrieve them:
riptides-cli ctl get oidcclient my-dashboard -o yamlUse these credentials in your application’s OIDC configuration.
Authentication Flow
Section titled “Authentication Flow”Once both resources are configured, the authentication flow works as follows:
- User visits the Riptides UI (or runs a
kubectlcommand that requires auth). - Riptides redirects to the IdP (e.g., GitHub’s OAuth authorization page).
- User authenticates with their IdP credentials (e.g., GitHub username/password + 2FA).
- IdP redirects back to the
redirectUrlconfigured on the OIDCClient, with an authorization code. - Riptides exchanges the code for an ID token and validates it against the IdentityProvider configuration (checking organization membership, domain, etc.).
- Session is established. The user can access the UI or issue authenticated API/kubectl commands.
For kubectl, the flow uses a local HTTP server:
# This triggers the OIDC flow — a browser window opens for authenticationriptides-cli ctl get workloadidentitiesStep 3: Grant access with ClusterRoleBindings
Section titled “Step 3: Grant access with ClusterRoleBindings”Configuring an IdentityProvider is not enough on its own. After authentication, Riptides checks Kubernetes RBAC to decide what the user can do. You grant access by binding the groups that your IdP returns to one of the predefined ClusterRoles:
| ClusterRole | Access |
|---|---|
riptides:users:viewer | Read-only access to all Riptides resources. |
riptides:users:editor | Full read/write access to all Riptides resources and Kubernetes Secrets in riptides-system. |
riptides:cluster-admin | Unrestricted access to all resources and verbs across the entire cluster. Use with caution. |
GitHub teams as groups
Section titled “GitHub teams as groups”When a user authenticates via the GitHub IdentityProvider, their GitHub team memberships are injected as OIDC groups claims in the form <org>:<team-slug>. For example, a member of the devs team in the abbazappa organization gets the group abbazappa:devs.
Important: Groups are populated from team memberships only. Being a member of an org without belonging to any team produces an empty
groupsclaim — the user can log in but will have no RBAC access. Make sure the users you want to grant access are in at least one GitHub team.
Bind a team group to the editor role:
apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: riptides-github-devs-editorroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: riptides:users:editorsubjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: "abbazappa:devs"riptides-cli ctl apply -f clusterrolebinding-devs.yamlAny member of abbazappa/devs who logs in with GitHub will now have editor access. Adding or removing someone from the GitHub team takes effect on their next login — no Kubernetes changes required.
For read-only access (e.g. for an ops team):
subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: "abbazappa:ops"roleRef: kind: ClusterRole name: riptides:users:viewer apiGroup: rbac.authorization.k8s.ioFor nested teams the group name includes the full parent chain: abbazappa:platform:devs.
Other providers
Section titled “Other providers”The same pattern works for any IdentityProvider. The group names in the binding just need to match whatever groups claim the IdP returns:
| Provider | Groups claim format |
|---|---|
| GitHub | <org>:<team-slug> (e.g. abbazappa:devs), or <org>:<parent>:<child> for nested teams |
| Google / OIDC | Groups returned in the IdP’s groups claim |
| Entra (Azure AD) | Group object IDs or display names, depending on configuration |
Applying changes to an existing session
Section titled “Applying changes to an existing session”OIDC tokens are cached locally by the oidc-login plugin. If you already have a valid cached token, creating or updating a ClusterRoleBinding will not take effect until the token is refreshed. Force a fresh login by clearing the token cache:
kubectl oidc-login cleanThen run any kubectl command — the plugin will open a browser for re-authentication and the new token will include the updated groups.
Multiple Identity Providers
Section titled “Multiple Identity Providers”You can configure multiple IdentityProviders simultaneously. The login screen will show all available providers, and users choose which one to authenticate with.
riptides-cli ctl get identityprovider -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.state}{"\n"}{end}'Verification
Section titled “Verification”-
Check that each IdentityProvider reached
Availablestate:Terminal window riptides-cli ctl get identityprovider -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.state}{"\n"}{end}' -
Check that the OIDCClient exists:
Terminal window riptides-cli ctl get oidcclient -
Open the Riptides UI in a browser. You should see a login page with your configured identity provider(s). Click the provider name, authenticate, and confirm you are redirected back to the UI with an active session.
-
Run any Riptides command and confirm it completes successfully:
Terminal window riptides-cli ctl get workloadidentities