Single Sign-On for HashiCorp Vault with Keycloak (OIDC)

Guilliano Molaire Guilliano Molaire 13 min read

Last updated: August 2026

HashiCorp Vault supports OIDC login through its built-in OIDC auth method, which lets you point Vault at your Keycloak realm’s discovery URL and delegate all identity decisions to Keycloak. You register Vault as a confidential OIDC client in your Keycloak realm with two specific redirect URIs, one for the browser UI callback and one for the CLI’s localhost callback, then add a groups protocol mapper so Vault can read group membership from the token and automatically assign policies. The result is a fully SSO-enabled Vault deployment where engineers log in with their company Keycloak credentials and inherit the right permissions without any manual Vault user management.

If your team already uses Keycloak for SSO, extending that to Vault is one of the highest-leverage things you can do. It eliminates a separate set of Vault usernames and passwords, centralises access in the identity layer you already manage, and gives you Keycloak’s audit trail for every Vault login. This tutorial walks through the complete configuration from scratch: enabling the auth method, creating the Keycloak client, wiring up the groups claim, creating the Vault role, mapping groups to policies, and verifying login through both the UI and the CLI. For a broader view of how SSO fits into a mature identity architecture, see our SSO implementation guide for developers.

How Vault’s OIDC auth method works

Before touching any configuration, it helps to understand what Vault’s OIDC auth method actually does. When a user initiates a login, Vault redirects their browser to Keycloak’s authorization endpoint. Keycloak authenticates the user, issues an ID token and access token, and redirects back to Vault’s callback URL. Vault validates the token signature against Keycloak’s JWKS endpoint (discovered automatically via the realm’s .well-known/openid-configuration URL), extracts the claims you specify, typically sub for the user identity and a custom groups claim for group membership, and maps those claims to Vault policies.

The OIDC auth method is a superset of Vault’s JWT auth method. Both use the same underlying auth/jwt plugin path; the difference is that OIDC uses the browser-based redirect flow while JWT validates a bearer token directly. This tutorial uses the OIDC flow, which is the right choice for interactive human login. For machine-to-machine scenarios (CI/CD pipelines, for example), the JWT method with a Keycloak service account token is a better fit, but that is a separate topic.

Understanding the protocol at this level matters because the most common configuration errors, redirect URI mismatches, missing claims, policy binding failures, all stem from a gap between what Vault expects and what Keycloak sends. The sections below are ordered to eliminate each failure point in turn. If you are new to OIDC itself, our OpenID Connect explainer for developers covers the token flow in depth.

Prerequisites

  • A running Keycloak 26.x instance. The realm discovery URL follows the pattern https://<keycloak-host>/realms/<realm-name>.
  • A Vault cluster (any edition, 1.13+). You need vault CLI access with a token that has auth/ mount permissions.
  • The Keycloak realm where your engineers already have accounts, or a dedicated realm for infrastructure access.
  • Network connectivity between the Vault server and Keycloak (Vault fetches the JWKS endpoint server-side during token validation).

Step 1, Enable the OIDC auth method in Vault

Vault ships with the OIDC/JWT auth method available but not mounted. Enable it at the default path:

vault auth enable oidc

If you prefer a custom mount path (for example, to run multiple OIDC providers simultaneously), specify it with -path:

vault auth enable -path=keycloak oidc

This tutorial uses the default oidc path throughout. Adjust the auth/oidc/ prefix in every subsequent command if you chose a custom path.

Step 2, Create the Keycloak OIDC client

In the Keycloak Admin Console, navigate to your realm and open Clients > Create client.

Basic settings

Field Value
Client type OpenID Connect
Client ID vault (or any identifier you choose, you will reference this in Vault config)
Name HashiCorp Vault

Click Next.

Capability config

Field Value
Client authentication On (this makes the client confidential)
Authorization Off
Standard flow Enabled
Direct access grants Disabled

Confidential clients send a client_secret along with every token request, which Vault supports and which is required for server-to-server token validation. Public clients are not appropriate here.

Login settings, the two redirect URIs

This is the step that causes the most friction. Vault needs two redirect URIs registered in Keycloak:

  1. UI callback: for browser-based login through the Vault web interface:
    https://<vault-host>:8200/ui/vault/auth/oidc/oidc/callback
  2. CLI callback: for vault login -method=oidc from the terminal, which spins up a temporary local HTTP server:
    http://localhost:8250/oidc/callback

Add both to the Valid redirect URIs field. If you skip the CLI URI, the vault login -method=oidc command will fail with a redirect_uri_mismatch error even though the UI login works fine. If you skip the UI URI, the browser flow breaks. Both are required for full functionality.

Also set Web origins to + (which tells Keycloak to allow CORS from any redirect URI origin) or to the explicit Vault hostname if you want tighter control.

Save the client. Then open the Credentials tab and copy the Client secret: you will need it in Step 4.

Step 3, Add the groups protocol mapper

By default, Keycloak does not include group membership in the ID token. You need to add a protocol mapper that injects a groups claim. This is the mechanism Vault uses to determine which policies to assign.

In the Keycloak Admin Console, open the vault client you just created. Navigate to Client scopes and click the dedicated client scope that was auto-created (it follows the pattern vault-dedicated). Inside that scope, go to Mappers > Add mapper > By configuration, then select Group Membership.

Configure the mapper:

Field Value
Name groups
Token claim name groups
Full group path Off (send just the group name, not /engineering/backend)
Add to ID token On
Add to access token On
Add to userinfo On

The Full group path setting matters. If you enable it, the claim value is /vault-admins instead of vault-admins. Vault’s groups_claim matching works against the raw string, so you need to know which format to expect and configure your external group aliases accordingly. Keeping it off (short names) is simpler for most setups.

Understanding how Keycloak scopes and claims interact in more detail is covered in our post on Keycloak client scopes vs. roles explained.

Alternative: use roles instead of groups

If your organisation models access via Keycloak realm roles or client roles rather than groups, you can use the User Realm Role or User Client Role mapper instead, with a token claim name of roles (or any name you choose), and then set groups_claim to roles in the Vault role configuration. The principle is the same: pick a claim name, add the mapper, and reference that claim name consistently in Vault.

Step 4, Configure Vault’s OIDC auth method

With the Keycloak client created and the client secret in hand, configure the auth method:

vault write auth/oidc/config 
  oidc_discovery_url="https://<keycloak-host>/realms/<realm-name>" 
  oidc_client_id="vault" 
  oidc_client_secret="<paste-client-secret-here>" 
  default_role="default"

The oidc_discovery_url points Vault at the realm’s well-known configuration endpoint. Vault appends /.well-known/openid-configuration automatically to discover the authorization endpoint, token endpoint, and JWKS URI. You never need to specify those individually.

default_role sets which role Vault uses when a user logs in without specifying one. You will create this role in the next step.

Step 5, Create the Vault OIDC role

A Vault OIDC role ties together the claim mappings, policy assignments, and allowed redirect URIs. Create a default role that applies to all Keycloak users, with policy assignment driven by the groups claim:

vault write auth/oidc/role/default 
  bound_audiences="vault" 
  user_claim="sub" 
  groups_claim="groups" 
  allowed_redirect_uris="https://<vault-host>:8200/ui/vault/auth/oidc/oidc/callback,http://localhost:8250/oidc/callback" 
  token_policies="default" 
  token_ttl="1h" 
  token_max_ttl="4h"

Key parameters explained:

  • bound_audiences, must match the aud claim in the token. Keycloak sets this to the client ID (vault), so this value must match.
  • user_claim, the claim Vault uses as the local entity alias. sub (the Keycloak user UUID) is the most stable choice. Avoid preferred_username since usernames can change.
  • groups_claim, the claim name you set in the Keycloak mapper. Must match exactly.
  • allowed_redirect_uris, the same two URIs you registered in Keycloak. Vault validates the redirect URI on every login attempt; mismatches cause immediate failures.
  • token_policies, baseline policies every authenticated user gets. default is a built-in Vault policy with minimal read permissions.

The groups_claim is what enables dynamic policy assignment per group without creating individual role entries per team. Vault reads the claim value as a list of group names and looks for matching external group aliases to determine additional policies.

Step 6, Map Keycloak groups to Vault policies

This step is the most operationally significant: it determines which Vault paths each Keycloak group can access. The mechanism is Vault’s external groups with group aliases pointing at the OIDC auth method.

First, identify the accessor of the OIDC auth method (you need it to create the alias):

vault auth list -format=json | jq -r '.["oidc/"].accessor'

Save that accessor string. Now, for each Keycloak group you want to map, create an external group in Vault and bind a policy to it:

# Create the external group for vault-admins
vault write identity/group 
  name="vault-admins" 
  type="external" 
  policies="vault-admin-policy"

# Capture the group ID
GROUP_ID=$(vault read -field=id identity/group/name/vault-admins)

# Create the group alias linking the group name to the OIDC accessor
vault write identity/group-alias 
  name="vault-admins" 
  canonical_id="$GROUP_ID" 
  mount_accessor="<oidc-accessor>"

The name in the group alias must exactly match the value that will appear in the groups claim token. If your Keycloak group is named vault-admins, the alias name must be vault-admins.

Repeat this pattern for every group you want to map. A typical mapping table looks like this:

Keycloak Group Vault External Group Vault Policy Access Level
vault-admins vault-admins vault-admin-policy Full read/write on all paths
vault-ops vault-ops vault-ops-policy Read/write on secret/ops/*
vault-dev vault-dev vault-dev-policy Read on secret/dev/*
vault-readonly vault-readonly vault-readonly-policy Read on secret/shared/*

For the access control model to make sense, each policy should be a Vault HCL policy file stored in version control and applied with vault policy write. For example, vault-dev-policy.hcl:

path "secret/data/dev/*" {
  capabilities = ["read", "list"]
}

path "secret/metadata/dev/*" {
  capabilities = ["list"]
}

Apply it:

vault policy write vault-dev-policy vault-dev-policy.hcl

This role-based policy structure maps closely to the principle of least privilege. For a deeper treatment of role-based access control design, see our guide on RBAC and protecting digital access.

Step 7, Log in via the Vault UI

Open https://<vault-host>:8200/ui. On the login screen, select OIDC from the method dropdown. Leave the role field as default (or specify a role name if you created multiple roles). Click Sign in with OIDC Provider.

Keycloak’s login page opens in the same browser window. The user authenticates with their standard Keycloak credentials. On success, Keycloak redirects to https://<vault-host>:8200/ui/vault/auth/oidc/oidc/callback with the authorization code. Vault exchanges the code for tokens, validates the ID token, reads the groups claim, and resolves the applicable group aliases. The user lands in the Vault UI with the policies their group memberships entitle them to.

Step 8, Log in via the Vault CLI

The CLI flow uses a browser redirect to a localhost callback. From a terminal with the vault binary and VAULT_ADDR set:

vault login -method=oidc role=default

Vault prints a URL and opens it in your default browser. You authenticate with Keycloak in the browser. Keycloak redirects to http://localhost:8250/oidc/callback, a temporary HTTP server that vault login spins up on port 8250. Vault captures the code, completes the token exchange, and prints a Vault token to the terminal:

Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.

Key                  Value
---                  -----
token                hvs.CAES...
token_accessor       abc123...
token_duration       1h
token_renewable      true
token_policies       ["default" "vault-dev-policy"]
identity_policies    []
policies             ["default" "vault-dev-policy"]
token_meta_role      default

The token_policies line shows both the baseline default policy and the group-derived vault-dev-policy, confirming that group claim mapping worked correctly.

This OIDC-based login pattern integrates naturally with a broader identity brokering architecture. If you are federating multiple identity providers into Keycloak before forwarding to Vault, see our guide on Keycloak identity brokering with GitHub social login for an example of adding upstream providers.

Troubleshooting common issues

Redirect URI mismatch

Symptom: Keycloak returns invalid_redirect_uri or redirect_uri_mismatch. Vault may show a generic OIDC callback error.

Cause: The URI Vault sends in the authorization request does not exactly match any URI in the Keycloak client’s Valid redirect URIs list. This is almost always a trailing slash, HTTP vs HTTPS, or port number discrepancy.

Fix: In the Keycloak Admin Console, open the vault client and compare the Valid redirect URIs field against the allowed_redirect_uris value in your Vault role. They must be byte-for-byte identical.

Groups claim not present in token

Symptom: Login succeeds but the user only gets the default policy, group-based policies are not applied.

Cause: The groups mapper is not configured correctly, or it is attached to a scope that is not included in the token by default.

Fix: In Keycloak, use the Evaluate tab under the vault client’s Client scopes section to simulate a token for a test user. Look for the groups claim in the decoded ID token. If it is absent, check that the mapper is attached to the vault-dedicated scope (not a separate optional scope that Vault is not requesting). Also verify that Add to ID token is enabled on the mapper.

Group alias name mismatch

Symptom: The groups claim is visible in the token (confirmed via Evaluate), but Vault still does not apply group policies.

Cause: The group alias name in Vault does not exactly match the string value in the token. This often happens when Full group path is enabled in the mapper (sending /vault-admins) but the alias is named vault-admins.

Fix: Decode a real ID token from a login attempt (use the JWT Token Analyzer to inspect the raw claims) and confirm the exact string value of each entry in the groups array. Update the Vault group alias name to match.

Port 8250 not reachable for CLI login

Symptom: vault login -method=oidc hangs or returns unable to start local HTTP server.

Cause: Port 8250 is blocked by a firewall or already in use. The vault login command must be able to bind localhost:8250.

Fix: Use -port to specify an alternate port, and add the corresponding http://localhost:<port>/oidc/callback URI to both the Keycloak client’s Valid redirect URIs and the Vault role’s allowed_redirect_uris.

Frequently asked questions

How do I set up Vault SSO with Keycloak?

Enable the OIDC auth method in Vault with vault auth enable oidc, then configure it with vault write auth/oidc/config pointing oidc_discovery_url at your Keycloak realm URL (https://<keycloak-host>/realms/<realm-name>). Create a confidential Keycloak client with both the UI and CLI redirect URIs registered, copy the client secret into the Vault config, and create a Vault OIDC role that maps the groups claim. Users can then log in at the Vault UI by selecting OIDC, or from the terminal with vault login -method=oidc.

How do I map Keycloak groups to Vault policies?

Add a Group Membership protocol mapper to the Keycloak vault client so the ID token carries a groups claim. In Vault, create external identity groups (vault write identity/group ... type=external policies=<policy-name>), then create group aliases that link each group name to the OIDC auth method’s accessor (vault write identity/group-alias name=<keycloak-group-name> mount_accessor=<oidc-accessor>). When a user logs in, Vault reads the groups claim, finds matching aliases, and applies the bound policies automatically.

What redirect URIs does Vault need for OIDC?

Vault requires two redirect URIs registered in Keycloak. The first is the UI callback: https://<vault-host>:8200/ui/vault/auth/oidc/oidc/callback. The second is the CLI callback: http://localhost:8250/oidc/callback. Both must be listed in the Keycloak client’s Valid redirect URIs and in the Vault role’s allowed_redirect_uris. Missing either one causes authentication failures for that specific login method.

Can I use Keycloak realm roles instead of groups for Vault policy mapping?

Yes. Add a User Realm Role mapper to the Keycloak client with a token claim name of roles (or any name), then set groups_claim="roles" in the Vault OIDC role. Create Vault external groups and aliases using the realm role names instead of group names. The alias lookup works the same way regardless of whether the claim carries group names or role names.

How do I verify the groups claim is being sent correctly?

In the Keycloak Admin Console, open the vault client, navigate to Client scopes, click the Evaluate tab, enter a test username, and click Generated ID token. Inspect the decoded JSON for the groups key and its values. You can also decode a live ID token using the JWT Token Analyzer at any point after a real login attempt.

Conclusion

Connecting HashiCorp Vault to Keycloak via OIDC is a three-layer configuration: the Keycloak client (with both redirect URIs and the groups mapper), the Vault auth method config (pointing at the realm discovery URL), and the Vault role and external group aliases (wiring the groups claim to policies). The trickiest part is keeping the redirect URIs and the groups claim name consistent across all three layers, the troubleshooting section above covers the failure modes you are most likely to encounter.

Once the integration is in place, every engineer who already has a Keycloak account can log into Vault without a separate credential. Group membership changes in Keycloak propagate to Vault on the next login, with no manual Vault user management required. The audit trail for every Vault login is visible in Keycloak’s event log alongside all other authentication events.

If you are running Keycloak yourself, the operational overhead of keeping it patched, scaled, and highly available can be significant. Skycloak provides managed Keycloak hosting with automatic updates, high availability, and pre-configured OIDC client templates, so you can focus on integrating Vault rather than operating Keycloak.

Tired of running Keycloak yourself?

Skycloak runs real upstream Keycloak for you with a 99.99% SLA. No fork, no lock-in, just managed Keycloak that stays patched and on call so you don't have to.

Guilliano Molaire
Written by
Founder

Guilliano is the founder of Skycloak and a cloud infrastructure specialist with deep expertise in product development and scaling SaaS products. He discovered Keycloak while consulting on enterprise IAM and built Skycloak to make managed Keycloak accessible to teams of every size.

Start Free Trial Talk to Sales
© 2026 Skycloak. All Rights Reserved. Design by Yasser Soliman