.. _keycloak-infrastructure-setup: Keycloak Infrastructure Setup ============================== This guide walks you through setting up `Keycloak `_ as an OpenID Connect identity provider for use with ``auth-middleware``'s :doc:`../oidc_provider`. It covers creating a realm and client, mapping groups into the token, creating users, and testing the setup. Prerequisites ============= Before starting, ensure you have: - A running Keycloak instance with admin access - Access to the Keycloak admin console, normally at ``https://keycloak.example.com/admin/`` Step 1: Create a Realm ======================= Realms isolate a set of users, clients, and roles from each other. Most applications get their own realm. 1. **Open the realm dropdown** (top-left of the admin console) → **Create Realm** 2. **Realm name**: e.g. ``myapp`` 3. Click **Create** All following steps assume you're working inside this realm. Step 2: Create a Client ======================== 1. **Navigate to Clients** - Go to **Clients** → **Create client** 2. **General Settings** - **Client type**: ``OpenID Connect`` - **Client ID**: e.g. ``my-app`` — you'll need this for ``OidcProviderSettings.audience`` - Click **Next** 3. **Capability Config** - **Client authentication**: **On** for a confidential client that can keep a secret (recommended for server-side apps), **Off** for a public client (SPA/mobile) - **Authentication flow**: enable the flows you need: - **Standard flow** (authorization code) — for browser-based login - **Direct access grants** — for the Resource Owner Password flow (useful for testing) - **Service accounts roles** — for machine-to-machine, client-credentials tokens - Click **Next** 4. **Login Settings** - **Valid redirect URIs**: your application's callback URL(s), if it performs the login flow directly - Click **Save** 5. **Client Secret** (confidential clients only) - Go to the client's **Credentials** tab to find the generated **Client secret** — only needed if your application performs the OAuth2 login flow itself (``auth-middleware`` only verifies tokens, it doesn't need the secret) .. _keycloak-groups-claim: Step 3: Include Groups in the Token (Optional) ================================================ To use ``OidcProviderSettings.groups_claim`` (instead of a separate :class:`~auth_middleware.contracts.groups_provider.GroupsProvider`), add a group-membership mapper: 1. **Navigate to Client Scopes** - Go to **Client scopes**, and either edit the client's dedicated scope (``my-app-dedicated``) or create a new reusable scope (e.g. ``groups``) and assign it to the client under the client's **Client scopes** tab 2. **Add a Mapper** - Open the scope, go to the **Mappers** tab → **Add mapper** → **By configuration** → **Group Membership** - **Name**: ``groups`` - **Token Claim Name**: ``groups`` - **Full group path**: **Off** (so you get plain group names like ``admin`` instead of ``/admin``) - **Add to ID token**: **On** - **Add to access token**: **On** (needed if your application authenticates with access tokens rather than ID tokens) - Click **Save** Step 4: Create Groups and Users ================================ 1. **Create Groups** - Go to **Groups** → **Create group**, name it e.g. ``admin`` - Repeat for any other groups your application needs (e.g. ``user``) 2. **Create Users** - Go to **Users** → **Add user**, fill in username/email - After creating the user, go to the **Credentials** tab to set a password (toggle **Temporary** off for a permanent password in test setups) - Go to the **Groups** tab and join the user to a group Step 5: Testing Your Setup ============================ Fetch the discovery document to confirm the realm is reachable: .. code-block:: bash curl https://keycloak.example.com/realms/myapp/.well-known/openid-configuration It should return a JSON document including ``issuer`` and ``jwks_uri``. To obtain a token for testing (Direct Access Grants / Resource Owner Password flow): .. code-block:: bash curl -X POST https://keycloak.example.com/realms/myapp/protocol/openid-connect/token \ -d "grant_type=password" \ -d "client_id=my-app" \ -d "client_secret=your-client-secret" \ -d "username=user@example.com" \ -d "password=user_password" Or, for machine-to-machine testing (Client Credentials flow): .. code-block:: bash curl -X POST https://keycloak.example.com/realms/myapp/protocol/openid-connect/token \ -d "grant_type=client_credentials" \ -d "client_id=my-app" \ -d "client_secret=your-client-secret" Configuration Summary ====================== .. code-block:: yaml Issuer: https://keycloak.example.com/realms/myapp Client ID: my-app Discovery URL: https://keycloak.example.com/realms/myapp/.well-known/openid-configuration Configure auth-middleware ========================== .. code-block:: python from auth_middleware import JwtAuthMiddleware from auth_middleware.providers.oidc.oidc_provider import OidcProvider from auth_middleware.providers.oidc.oidc_provider_settings import ( OidcProviderSettings, ) auth_settings = OidcProviderSettings( issuer="https://keycloak.example.com/realms/myapp", audience="my-app", groups_claim="groups", # only if you completed Step 3 ) app.add_middleware( JwtAuthMiddleware, auth_provider=OidcProvider(settings=auth_settings), ) Use these values as described in the :doc:`../oidc_provider` documentation. Troubleshooting ================ 1. **401 "No public key found"** - Confirm the discovery document's ``jwks_uri`` (usually ``https://keycloak.example.com/realms/myapp/protocol/openid-connect/certs``) is reachable from your application server - Realm keys are managed under **Realm settings** → **Keys** — ensure an active RS256 key pair exists 2. **Groups missing from the token** - Confirm the **Group Membership** mapper (Step 3) is attached to a scope the client actually requests - Check whether your token is an access token or ID token, and that the mapper is enabled for the one you're verifying - Alternatively, use a dedicated :class:`~auth_middleware.contracts.groups_provider.GroupsProvider` — it takes precedence over ``groups_claim`` when both are configured, so it's the more robust option if you'd rather not maintain the mapper 3. **"aud" mismatch / token rejected** - By default, Keycloak access tokens may not include your client in the ``aud`` claim unless "Add to audience" is configured. Either add an **Audience** mapper for your client, or omit ``OidcProviderSettings.audience`` and rely on ``iss`` validation alone (less strict, but works with default Keycloak tokens) 4. **Wrong issuer** - The issuer is realm-scoped: ``https:///realms/`` — not the client name or a per-application path Security Best Practices ======================== 1. Use **confidential** clients with client authentication enabled for server-side applications 2. Disable **Direct access grants** and **Implicit flow** in production unless you specifically need them 3. Rotate realm signing keys periodically (**Realm settings** → **Keys**) 4. Scope group/role mappers to only the claims your application needs 5. Serve Keycloak over HTTPS only, and keep it patched — it is a critical security component Next Steps ========== 1. Configure ``auth-middleware`` with your Keycloak settings as shown above 2. Test the authentication flow end-to-end from your application 3. Implement authorization rules using ``require_groups``/``require_roles``/``require_permissions`` 4. Deploy Keycloak and your application with production-grade TLS and monitoring For implementation details, see the :doc:`../oidc_provider` documentation.