Creating OIDCClient Resources¶
OIDCClient is the Custom Resource that tells the operator which Authentik application to read OIDC credentials from and where to write them as a Kubernetes Secret.
Where to Place OIDCClient CRs¶
OIDCClient CRs belong in the consumer application's Helm chart, not in the operator chart. This keeps OIDC configuration close to the application that uses it:
services/apps/kube-prometheus-stack/templates/oidcclient.yaml # Grafana
services/apps/open-webui/templates/oidcclient.yaml # OpenWebUI
k3s-core/modules/argocd/chart/templates/oidcclient.yaml # ArgoCD
The operator chart only contains the operator itself, RBAC, bootstrap Job, and CRD definitions. OIDCClient CRs can be created before the operator is running -- the operator will reconcile them once it starts.
CRD Spec Reference¶
Every OIDCClient CR follows this structure:
apiVersion: auth.kettleofketchup/v1alpha1
kind: OIDCClient
metadata:
name: <unique-name> # Cluster-scoped unique name for this binding
spec:
authentik:
applicationSlug: <string> # (Required) Slug of the Authentik application
target:
namespace: <string> # (Required) Namespace for the generated Secret
secretName: <string> # (Required) Name of the generated Secret
secretProfile: <string> # Profile for secret key mapping (default: generic)
secretOverrides: # (Optional) Extra or overridden key-value pairs
KEY_NAME: "value"
rolloutRestart: # (Optional) Restart a workload on secret changes
enabled: true
targetRef:
kind: Deployment|StatefulSet
name: <workload-name>
namespace: <workload-namespace>
Field Details¶
spec.authentik.applicationSlug¶
The slug of the Authentik application to read OIDC credentials from. This must match the slug defined in your Authentik blueprint or application configuration.
The operator performs a two-step API lookup:
GET /api/v3/core/applications/{slug}/to find the applicationGET /api/v3/providers/oauth2/?application={pk}to retrieveclient_idandclient_secret
spec.target¶
Defines where the operator writes the OIDC credentials Secret:
namespace-- The namespace where the Secret is created. Does not need to be the operator namespace.secretName-- The name of the Secret resource.
The operator creates the Secret if it does not exist, or updates it if the content has changed.
spec.secretProfile¶
Selects a built-in key mapping profile that determines how OIDC data is mapped to Secret keys. Valid values:
| Profile | Use Case |
|---|---|
grafana | Grafana GF_AUTH_GENERIC_OAUTH_* environment variables |
openwebui | OpenWebUI OAUTH_* / OPENID_* environment variables |
argocd | ArgoCD argocd-secret keys for Dex integration |
generic | Plain keys: clientId, clientSecret, authorizeUrl, etc. |
Default: generic
spec.secretOverrides¶
A string map that merges on top of the profile output. Use this to:
- Add application-specific settings (e.g. Grafana role mapping)
- Override default values (e.g. custom scopes)
- Inject extra static values the consuming app needs
Overrides take precedence over profile-generated keys with the same name.
spec.rolloutRestart¶
When enabled, the operator patches the target workload's pod template with an annotation containing the secret hash whenever the Secret content changes. This triggers a rolling restart so the application picks up the new credentials.
enabled-- Set totrueto activate (default:false)targetRef.kind--DeploymentorStatefulSettargetRef.name-- Name of the workloadtargetRef.namespace-- Namespace of the workload
Source Data¶
The operator derives these values from the Authentik API and the configured authentik.url:
| Variable | Source |
|---|---|
clientId | Authentik API — provider client ID |
clientSecret | Authentik API — provider client secret |
authorizeUrl | {baseURL}/application/o/authorize/ (global) |
tokenUrl | {baseURL}/application/o/token/ (global) |
userinfoUrl | {baseURL}/application/o/userinfo/ (global) |
issuerUrl | {baseURL}/application/o/{slug}/ (per-app) |
logoutUrl | {baseURL}/application/o/{slug}/end-session/ (per-app) |
scopes | openid email profile (default) |
Profiles map these source values to application-specific Secret keys.
Profile Examples¶
Grafana¶
apiVersion: auth.kettleofketchup/v1alpha1
kind: OIDCClient
metadata:
name: grafana-oidc
spec:
authentik:
applicationSlug: grafana
target:
namespace: monitoring
secretName: grafana-oauth
secretProfile: grafana
secretOverrides:
GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH: >-
contains(groups, 'admins') && 'Admin' || 'Viewer'
GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP: "true"
rolloutRestart:
enabled: true
targetRef:
kind: Deployment
name: kube-prometheus-stack-grafana
namespace: monitoring
The grafana profile generates keys matching Grafana's GF_AUTH_GENERIC_OAUTH_* environment variables. The example above adds secretOverrides for role mapping and sign-up configuration that are specific to each deployment.
Generated Secret keys:
| Secret Key | Source |
|---|---|
GF_AUTH_GENERIC_OAUTH_ENABLED | "true" (static) |
GF_AUTH_GENERIC_OAUTH_NAME | "authentik" (static) |
GF_AUTH_GENERIC_OAUTH_CLIENT_ID | clientId |
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET | clientSecret |
GF_AUTH_GENERIC_OAUTH_AUTH_URL | authorizeUrl |
GF_AUTH_GENERIC_OAUTH_TOKEN_URL | tokenUrl |
GF_AUTH_GENERIC_OAUTH_API_URL | userinfoUrl |
GF_AUTH_GENERIC_OAUTH_SCOPES | "openid email profile" |
OpenWebUI¶
apiVersion: auth.kettleofketchup/v1alpha1
kind: OIDCClient
metadata:
name: openwebui-oidc
spec:
authentik:
applicationSlug: open-webui
target:
namespace: open-webui
secretName: openwebui-oauth
secretProfile: openwebui
rolloutRestart:
enabled: true
targetRef:
kind: Deployment
name: open-webui
namespace: open-webui
The openwebui profile generates keys matching OpenWebUI's OAuth environment variables.
Generated Secret keys:
| Secret Key | Source |
|---|---|
ENABLE_OAUTH_SIGNUP | "true" (static) |
OAUTH_PROVIDER_NAME | "authentik" (static) |
OAUTH_CLIENT_ID | clientId |
OAUTH_CLIENT_SECRET | clientSecret |
OPENID_PROVIDER_URL | issuerUrl |
OAUTH_SCOPES | "openid email profile" |
ArgoCD¶
apiVersion: auth.kettleofketchup/v1alpha1
kind: OIDCClient
metadata:
name: argocd-oidc
spec:
authentik:
applicationSlug: argocd
target:
namespace: argocd
secretName: argocd-secret
secretProfile: argocd
The argocd profile writes keys into the argocd-secret Secret for Dex OIDC integration. The dex.config section in argocd-cm must be configured separately through ArgoCD Helm values to reference these keys.
Generated Secret keys:
| Secret Key | Source |
|---|---|
dex.authentik.clientSecret | clientSecret (referenced as $dex.authentik.clientSecret in Dex config) |
clientId | clientId (convenience key) |
issuerUrl | issuerUrl (convenience key) |
Generic¶
apiVersion: auth.kettleofketchup/v1alpha1
kind: OIDCClient
metadata:
name: myapp-oidc
spec:
authentik:
applicationSlug: my-application
target:
namespace: my-app
secretName: myapp-oidc-credentials
secretProfile: generic
The generic profile uses plain source variable names as Secret keys, suitable for any application that accepts standard OIDC configuration:
Generated Secret keys:
| Secret Key | Source |
|---|---|
clientId | clientId |
clientSecret | clientSecret |
authorizeUrl | authorizeUrl |
tokenUrl | tokenUrl |
userinfoUrl | userinfoUrl |
issuerUrl | issuerUrl |
scopes | "openid email profile" |
Secret Overrides¶
Use secretOverrides to add keys that the profile does not include, or to override profile defaults.
Adding extra keys¶
spec:
secretProfile: grafana
secretOverrides:
GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH: >-
contains(groups, 'admins') && 'Admin' || 'Viewer'
GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP: "true"
GF_AUTH_GENERIC_OAUTH_AUTO_LOGIN: "true"
Overriding profile defaults¶
The override replaces the profile's default scopes value.
Static-only secrets¶
Combine the generic profile with overrides to build a fully custom Secret:
spec:
secretProfile: generic
secretOverrides:
CUSTOM_OAUTH_ENABLED: "true"
CUSTOM_DISPLAY_NAME: "Corporate SSO"
Override values must be strings
All values in secretOverrides are strings. Booleans and numbers must be quoted: "true", "3600".
Rollout Restart¶
When the Secret content changes (detected via SHA256 hash comparison), the operator can trigger a rolling restart of a consuming workload.
spec:
rolloutRestart:
enabled: true
targetRef:
kind: Deployment # or StatefulSet
name: my-app
namespace: my-namespace
The operator patches a pod template annotation on the target workload:
This changes the pod template spec, causing Kubernetes to perform a rolling update.
Cross-namespace restarts
The target workload does not need to be in the same namespace as the OIDCClient CR. The operator has cluster-wide RBAC for Deployments and StatefulSets.
Checking Status¶
The operator sets status conditions on each OIDCClient CR. Check them with:
Example output:
NAME SLUG PROFILE TARGET NS READY SYNCED AGE
grafana-oidc grafana grafana monitoring True True 5m
argocd-oidc argocd argocd argocd True True 5m
openwebui-oidc open-webui openwebui open-webui True True 3m
For detailed status, use kubectl describe:
Status Conditions¶
| Condition | Meaning |
|---|---|
AuthentikProviderFound | The operator successfully found the OIDC provider in Authentik |
SecretSynced | The target Secret has been created/updated with current credentials |
RolloutTriggered | A rollout restart was triggered (only present when rollout is enabled) |
A condition with status: "False" indicates a problem. Check the condition's message field for details:
Common Patterns¶
Deploy OIDCClient with a Helm chart¶
Add an oidcclient.yaml template to your application's Helm chart:
apiVersion: auth.kettleofketchup/v1alpha1
kind: OIDCClient
metadata:
name: {{ include "myapp.fullname" . }}-oidc
spec:
authentik:
applicationSlug: {{ .Values.oidc.slug }}
target:
namespace: {{ .Release.Namespace }}
secretName: {{ include "myapp.fullname" . }}-oidc-credentials
secretProfile: generic
rolloutRestart:
enabled: true
targetRef:
kind: Deployment
name: {{ include "myapp.fullname" . }}
namespace: {{ .Release.Namespace }}
Conditional OIDC¶
Gate the OIDCClient on a Helm value so it is only created when OIDC is enabled:
{{- if .Values.oidc.enabled }}
apiVersion: auth.kettleofketchup/v1alpha1
kind: OIDCClient
metadata:
name: {{ include "myapp.fullname" . }}-oidc
spec:
authentik:
applicationSlug: {{ .Values.oidc.slug }}
target:
namespace: {{ .Release.Namespace }}
secretName: {{ .Values.oidc.secretName }}
secretProfile: generic
{{- end }}
Multiple profiles for the same application¶
If an application needs credentials in two different formats, create two OIDCClient CRs pointing to the same Authentik slug but different profiles:
---
apiVersion: auth.kettleofketchup/v1alpha1
kind: OIDCClient
metadata:
name: myapp-oidc-generic
spec:
authentik:
applicationSlug: my-application
target:
namespace: my-app
secretName: myapp-oidc-generic
secretProfile: generic
---
apiVersion: auth.kettleofketchup/v1alpha1
kind: OIDCClient
metadata:
name: myapp-oidc-custom
spec:
authentik:
applicationSlug: my-application
target:
namespace: my-app
secretName: myapp-oidc-custom
secretProfile: generic
secretOverrides:
OAUTH_ENDPOINT: "https://auth.example.com/application/o/my-application/"