Skip to content
cccskills
FreePublished on GitHub

auth:keycloak-confidential-client

Create confidential OAuth2 clients in Keycloak for server-to-service authentication

The English summary is being prepared. Showing the original description.

rossoctl/rossoctl303 stars(GitHub 303 + cccskills 0)
Works withKubernetes

Run score Not tested

See how to install

Files included (1)

  • SKILL.md5.6 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Keycloak Confidential Client Pattern

Create confidential OAuth2 clients in Keycloak for server-side applications using client credentials flow.

Table of Contents

Overview

Keycloak supports two types of OAuth2 clients:

  • Public clients: For browser-based SPAs using PKCE flow
  • Confidential clients: For server-side applications using client credentials flow

This skill focuses on confidential clients for service-to-service authentication.

Key Configuration

Required Settings for Client Credentials Flow

keycloak_admin.create_client({
    "clientId": "my-service",
    "name": "My Service Client",
    "enabled": True,
    "protocol": "openid-connect",
    "publicClient": False,  # This makes it a confidential client
    "serviceAccountsEnabled": True,  # REQUIRED for client credentials grant
    "standardFlowEnabled": False,  # No authorization code flow
    "directAccessGrantsEnabled": False,  # No password grant
})

Critical: serviceAccountsEnabled: True is REQUIRED for the client credentials grant type. Without this, the token endpoint will reject requests with invalid_grant.

Python Script Pattern

Use the python-keycloak library:

from keycloak import KeycloakAdmin

def create_confidential_client(keycloak_url, realm, admin_user, admin_pass, client_id):
    """Create a confidential OAuth2 client."""
    keycloak_admin = KeycloakAdmin(
        server_url=keycloak_url,
        username=admin_user,
        password=admin_pass,
        realm_name=realm,
        verify=True
    )

    # Create client
    keycloak_admin.create_client({
        "clientId": client_id,
        "enabled": True,
        "publicClient": False,
        "serviceAccountsEnabled": True,
        "standardFlowEnabled": False,
    })

    # Get client secret
    client_uuid = keycloak_admin.get_client_id(client_id)
    client_secret = keycloak_admin.get_client_secrets(client_uuid)["value"]

    return client_secret

Kubernetes Job Pattern

Deploy as a Kubernetes Job that runs during installation:

apiVersion: batch/v1
kind: Job
metadata:
  name: my-service-oauth-secret
  namespace: rossoctl-system
spec:
  template:
    spec:
      serviceAccountName: my-service-client-registration
      containers:
        - name: register
          image: python:3.11-slim
          command: ["python", "/scripts/register.py"]
          env:
            - name: KEYCLOAK_URL
              value: "http://keycloak-service.keycloak.svc.cluster.local:8080"
            - name: KEYCLOAK_ADMIN
              valueFrom:
                secretKeyRef:
                  name: keycloak-admin
                  key: username
            - name: KEYCLOAK_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: keycloak-admin
                  key: password
          volumeMounts:
            - name: scripts
              mountPath: /scripts
      restartPolicy: OnFailure
      volumes:
        - name: scripts
          configMap:
            name: my-service-oauth-script

RBAC Requirements

When creating secrets in other namespaces, you need cross-namespace RoleBindings:

# Role in target namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: secret-creator
  namespace: rossoctl-system
rules:
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["create", "get", "update", "patch"]

---
# RoleBinding to service account in source namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: keycloak-secret-creator
  namespace: rossoctl-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: secret-creator
subjects:
  - kind: ServiceAccount
    name: my-service-client-registration
    namespace: keycloak

SSL Certificate Handling

Option 1: Use Internal Keycloak URL (Recommended)

Avoid TLS complexity by using the internal service URL:

http://keycloak-service.keycloak.svc.cluster.local:8080

Option 2: Use OpenShift Trusted CA Bundle

Mount the pre-existing CA bundle:

volumeMounts:
  - name: trusted-ca
    mountPath: /etc/pki/ca-trust/extracted/pem
    readOnly: true
volumes:
  - name: trusted-ca
    configMap:
      name: config-trusted-cabundle
      items:
        - key: ca-bundle.crt
          path: tls-ca-bundle.pem

Secret Structure

Different consumers expect different secret key names:

MLflow

data:
  OIDC_CLIENT_ID: <base64>
  OIDC_CLIENT_SECRET: <base64>
  OIDC_TOKEN_URL: <base64>

Phoenix

data:
  PHOENIX_OAUTH2_CLIENT_ID: <base64>
  PHOENIX_OAUTH2_CLIENT_SECRET: <base64>

OTEL Collector

data:
  MLFLOW_CLIENT_ID: <base64>
  MLFLOW_CLIENT_SECRET: <base64>

Troubleshooting

Error: invalid_grant

  • Ensure serviceAccountsEnabled: True is set on the client
  • Check that the client secret is correct

Error: SSL certificate problem

  • Use internal Keycloak URL to avoid TLS issues
  • Or mount the trusted CA bundle

Error: Access denied

  • Check RoleBinding is in the correct namespace
  • Verify service account name matches

Related Skills

  • auth:otel-oauth2-exporter
  • openshift:trusted-ca-bundle

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

auth

Free

Authentication and authorization patterns for Rossoctl services

The English summary is being prepared. Showing the original description.

rossoctl/rossoctl303Updated Oct 25, 2026

Configure MLflow with mlflow-oidc-auth plugin for Keycloak OIDC authentication

The English summary is being prepared. Showing the original description.

rossoctl/rossoctl303Updated Oct 25, 2026

Configure OpenTelemetry Collector with OAuth2 authentication for trace export

The English summary is being prepared. Showing the original description.

rossoctl/rossoctl303Updated Oct 25, 2026

ci

Free

CI pipeline monitoring, status checks, and PR validation workflows

The English summary is being prepared. Showing the original description.

rossoctl/rossoctl303Updated Oct 25, 2026

Monitor running CI jobs, wait for completion, create tasks for results

The English summary is being prepared. Showing the original description.

rossoctl/rossoctl303Updated Oct 25, 2026

Check PR CI status - all checks, failures, test results, and artifacts

The English summary is being prepared. Showing the original description.

rossoctl/rossoctl303Updated Oct 25, 2026

See all skills by rossoctl

Report a problem with this skill