Let Product Teams Onboard Apps Without Handing Out Keycloak Admin

George Thomas George Thomas Updated July 30, 2026 9 min read

Last updated: July 2026

Once your IAM team serves more than a handful of product teams, app onboarding turns into a standoff. A team needs a client, they need it this sprint, and you have two obvious options: hand them the admin console and hope for the best, or become the ticket queue every launch waits on. Both are bad. There are only two patterns that hold up in the field, and they are: a self-service layer that talks to the Admin REST API on the team’s behalf, or Terraform pull requests your IAM team reviews. Pick based on how many teams you serve and how fluent they are in Terraform, not on which one sounds more sophisticated.

TL;DR

  • Pattern A (self-service layer): a thin app in front of Keycloak’s Admin REST API. Teams onboard themselves, nobody touches the admin console. Best at scale and with non-Terraform teams. Cost: you are now shipping and maintaining software.
  • Pattern B (Terraform PRs): teams write HCL, IAM reviews and merges. Best when teams already live in Terraform and you want config history for free. Cost: review becomes the bottleneck you were trying to escape.
  • Both are real. A large European retail group we spoke with runs A and B side by side, splitting by team, not by principle.
  • Do not default to “give them admin.” manage-clients is realm-wide, and it is a much bigger grant than it looks.

Why not just give product teams admin?

Because Keycloak’s built-in admin roles are blunter than most people expect. The realm-management client ships roles like manage-clients, create-client, and view-clients, and manage-clients means every client in the realm, not just the ones a team created. Out of the box there is no “you may edit your own app and nothing else.” That single role is the whole realm.

Three things go wrong, in order of how much they will ruin your quarter:

Redirect URIs are a security boundary, not a setting. Anyone who can edit a client can edit its redirect URIs, and a sloppy wildcard is how authorization codes walk out the door. The OAuth 2.0 Security Best Current Practice is blunt about this: authorization servers should use exact string matching for redirect URIs, precisely because loose matching enables code interception (RFC 9700, 2025). Handing that dial to twelve product teams means twelve chances to get it wrong, and one is enough.

Blast radius is realm-wide. The shared client your SSO depends on sits in the same list as the toy app someone is registering on a Friday. One accidental edit to the wrong row and you are debugging an org-wide login outage.

Your audit trail is probably not on. Keycloak can log admin events, but admin event logging is disabled by default per realm, and “include representation” (the part that tells you what actually changed) is a separate toggle. If you handed out admin and never enabled it, you have no answer to “who broke this and when.” Even with it on, an event log tells you what happened after the fact. It does not stop anything.

The tempting escape hatch is a realm per team. It is a genuine isolation boundary, so it does fix blast radius. It also multiplies your operational surface by the number of teams and fragments the SSO story you presumably adopted Keycloak to get. Realms are for isolating tenants, not for apologizing for permissions. If your teams’ users need to move between apps, a realm per team is a very expensive way to lose single sign-on.

Pattern A: what does a self-service layer actually look like?

A thin internal app sits in front of Keycloak. Product teams log into it (with SSO, obviously), fill in a short form, and get a working client. The app holds the privileged credentials. The team never sees the admin console. Here is how one senior IAM engineer at a large European retail group described their setup:

“We provide them a self-service where they can easily configure their own client and be onboarded… they don’t even have admin access to the Keycloak. And they can also, through this self-service, configure permissions like for individual team member.”

That last part is the bit people miss. The self-service layer is not just a client factory. It owns who on the team can change what, at the individual member level, which is exactly the granularity Keycloak’s stock admin roles refuse to give you.

The mechanics are unremarkable, which is the point:

  1. A dedicated client with a service account. Confidential client, service account enabled, granted a scoped set of realm-management roles (create-client, view-clients, and only what you actually need). This is the only identity with real power, and it lives in one place you can rotate and monitor.
  2. Your app enforces policy, not Keycloak. Team membership, ownership, naming, and redirect URI rules are decided in your code before any call goes out.
  3. It calls the Admin REST API. Client creation, updates, and secret rotation all go through the standard admin endpoints.

What to expose, and what to never expose

The whole value is in this list. Get it wrong and you have rebuilt admin access with extra steps.

Safe to expose: client name and description, redirect URIs validated against an allowlist of domains the team owns, post-logout redirect URIs, web origins, PKCE settings, client secret rotation, and team member permissions on the client.

Never expose: protocol mappers, “full scope allowed,” role scope mappings, service account role assignment, and token lifespans. Protocol mappers are the sharp one. A team that can add mappers can mint whatever claims they like into their own tokens, including the groups or roles claims your other services trust for authorization. That is not client configuration. That is privilege escalation with a nice UI.

Note the distinction from restricting which users can log into a client: that is about who can use the app. This is about who can configure it. Different problem, and teams regularly conflate them.

Do you need fine-grained admin permissions?

Maybe, and read the label first. Keycloak has fine-grained admin permissions built on Authorization Services attached to the realm-management client, which lets you scope management down to a specific client instead of all of them. It is still a preview feature in the 26.x line, which means it is off by default and you own the risk of running it in production.

Here is the honest take: if you are building a self-service layer anyway, you may not need it. Your app is already the policy engine, and it can hold a single scoped service account. Fine-grained admin permissions matter most when you want the guarantee enforced inside Keycloak rather than only in your code, which is a real thing to want if your auditors ask who could theoretically do what.

Pattern B: Terraform PRs, or GitOps for realm config

Same governance goal, completely different surface. Teams describe their client in HCL, open a pull request, and the IAM team reviews and merges. CI applies it. From the same engineer:

“Some teams are able to create, for example, like a pull request of the Terraform script where they configure their own clients and they only do the review.”

“They only do the review” is doing a lot of work in that sentence, and it is the whole trade. You write no software. You get config history, diffs, rollbacks, and a review record for free, because Git already does all of that. What you get in exchange is a queue with your name on it.

If you are starting from scratch here, our guide on using Terraform to set up and configure Keycloak covers the basics, and advanced Terraform patterns covers the modules and workspaces you will want once more than one team is committing.

What should IAM actually gate on?

Review everything and you are the bottleneck. Review nothing and you are a rubber stamp with extra latency. Gate on the things that are irreversible or cross team boundaries:

  • Redirect URI allowlists. Exact URIs on domains the team demonstrably owns. No wildcards in production. Automate this one in CI so it fails before a human reads it.
  • Naming and ownership. A client ID convention and a required owner tag. Unowned clients are how you end up with a realm full of things nobody will let you delete.
  • Scope and role grants. Any request for roles outside the team’s own client is a real review, every time.
  • Protocol mappers and flows. Same reasoning as Pattern A. If a PR adds a mapper, that is an IAM decision, not a formality.
  • Public vs confidential. A public client asking for elevated grants deserves a conversation.

The move that makes this pattern work is a module. Publish a product-app-client module with the safe surface as inputs and everything dangerous hardcoded. Teams instantiate it with five lines. Review shrinks to “are these five values sane,” which takes ninety seconds instead of thirty minutes.

What can Terraform actually manage here?

Worth being precise, because this trips people up. “Manage Keycloak with Terraform” covers three different jobs, and no single provider owns all three:

  1. Provision the instance and platform. The cluster, custom domains, WAF, SIEM streaming, branding. The Skycloak provider does this. The admin API has no concept of it.
  2. Bootstrap the realm. Realms, users, roles, groups, basic clients, identity providers, SMTP. Both providers cover this.
  3. Configure the realm in depth. Authentication flows, protocol mappers, client scopes, token and password policies. This is the community keycloak/keycloak provider’s turf, and it is deliberately out of scope for the Skycloak provider.

So for Pattern B: the Skycloak provider can provision your managed instance and create basic clients, which covers a lot of straightforward app onboarding. The moment a PR touches mappers, client scopes, or auth flows, that is the community provider, pointed at the same cluster. Plenty of teams run both in one project, and we wrote up how the two compare and combine. Don’t let anyone (us included) tell you one provider does the lot.

So which pattern should you pick?

Signal Self-service layer (A) Terraform PRs (B)
Teams served 10+, growing Under ~10, stable
Terraform literacy Low or mixed High, already in the workflow
IAM review capacity Scarce You can absorb a steady PR trickle
Onboarding speed Minutes, no human Hours to days, human gated
Per-member permissions Native to the design Awkward, Git owns access instead
Audit trail You build it Free, it’s Git history
Upfront cost You ship and maintain an app A module and a CI check
Fails when Nobody owns the tool Reviewers go on holiday

The retail group runs both, and that is the actual lesson. Their Terraform-fluent teams send PRs. Everyone else uses the self-service portal. Splitting by team capability rather than by architectural principle is not a compromise, it’s just correct. Pattern B for the teams who already speak HCL, Pattern A for the long tail, one governance model underneath.

If you want the shape of A without building the whole thing, scoped team management covers the “who on this team can touch what” half, which is usually the half people underestimate.

One more distinction worth keeping straight: this post is about onboarding applications. Governing user access requests (someone needs a role or group) is a different workflow with different approval semantics, and we covered it separately in identity governance workflows.

FAQ

Can I give a team admin access to only their own client?
Not with stock admin roles. manage-clients in the realm-management client applies to every client in the realm. Per-client scoping requires fine-grained admin permissions (a preview feature in 26.x) or a self-service layer that enforces ownership in your own code before calling the Admin REST API.

Do I need the fine-grained admin permissions preview feature?
Only if you want Keycloak itself to enforce the boundary. If your self-service app holds the one scoped service account and makes every policy decision, the enforcement already lives in your code. Reach for the preview feature when auditors want the guarantee in the server, not the app.

Isn’t a realm per team simpler?
It isolates well and destroys SSO between your apps. Realms are a tenant boundary. Using them to work around permissions multiplies your operational surface by team count and fragments the single sign-on you adopted Keycloak for.

What’s the one thing to automate in Terraform PR review?
Redirect URI validation. Exact strings, on domains the team owns, no wildcards. Fail it in CI so no human is the last line of defense against a * that ends in a code interception writeup.

What if a team doesn’t know Terraform?
Don’t teach them Terraform to register an app. That’s what Pattern A is for. Mixed fluency across teams is the normal case, and it’s the reason running both patterns is a legitimate answer rather than a sign of indecision.

Can the Skycloak Terraform provider do all of this?
It provisions the managed instance and platform, and creates realm basics including basic clients, which covers standard app onboarding. Deep realm configuration (authentication flows, protocol mappers, client scopes, token and password policies) needs the community keycloak/keycloak provider. Many teams run both against the same cluster.


The pattern matters less than the principle: nobody needs the admin console to register an app. Put something in between, whether that’s your own portal or a pull request template, and the console goes back to being what it should be, a tool for the handful of people who run the platform.

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.

George Thomas
Written by
Senior IAM Engineer

George is a senior IAM engineer with 23+ years in software engineering, including 14+ years specializing in identity and access management. He designs and modernizes enterprise IAM platforms with deep expertise in Keycloak, OAuth 2.0, OpenID Connect, SAML, and identity federation across cloud and hybrid environments. Previously at Trianz and a long-term contributor to Entrust IAM product engineering, George authors Skycloak's technical Keycloak tutorials.

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