A Keycloak-based IAM lab focused on scalable authentication, RBAC, and access control across multiple services.
Project Type: IAM Architecture Lab
Technology: Keycloak, Docker, Postman
Protocols: OAuth2, OpenID Connect, JWT
Objective: Build a secure, scalable and manageable Keycloak-based IAM setup, with RBAC, token-based authentication and a clear access model across multiple services.
Focus: Keycloak configuration, client and role design, service integration, and keeping the access model clear as the platform grows.
This project focuses on building a centralised IAM setup using Keycloak for a multi-service banking-style environment.
The aim was to create something that is secure, scalable, and easy to manage — not just something that works, but something that can grow without becoming difficult to maintain.
I structured the environment around multiple applications and APIs, each with their own roles and access requirements, and built a clear RBAC model to keep things consistent.
A big part of the design was making sure the access model stayed understandable as more users, services and roles were added, rather than becoming harder to maintain over time.
Although the bank itself is fictional, the setup mirrors the kind of IAM structure you would expect in a real environment with multiple internal services and separate access boundaries.
While this was built as a lab, the structure was designed the same way I would approach a real Keycloak environment: keep the access model clear, keep service boundaries explicit, and avoid anything that becomes difficult to support as the platform grows.
User (Postman / Application)
↓
Keycloak (Identity Provider)
↓
JWT Access Token (roles + claims)
↓
Applications / APIs
Keycloak acts as the central identity provider. It handles authentication, issues JWTs, and gives one place to manage clients, roles, groups and token claims, which helps keep access control consistent across services as the environment grows.
Realm: northstar-bank
The client structure was designed to reflect a microservice-style environment, where different applications and APIs have distinct trust boundaries and access requirements.
teller → - view_branch_customers - initiate_cash_operation - read_account_data - create_payment
This approach keeps the model easier to support over time, because changes can be made at role level without reworking access on a per-user basis.
branches
├── London
│ └── tellers
└── Tokyo
└── managers
Using groups in this way reduces manual administration and makes access changes easier to manage when teams, branches or internal structures change.
david.teller → branch_id = London
/realms/northstar-bank/protocol/openid-connect/token
Testing the token flow directly made it easier to confirm that authentication, client setup and token issuance were all working as expected before relying on the setup from an application layer.
After the token was issued, I checked it to make sure the expected roles and claims were present.
"realm_access": { "roles": ["teller"] }
"branch_id": "London"
This was mainly to confirm that the RBAC model and custom claim mapping were both working as expected.
This was important because downstream services need a reliable token structure if they are going to make consistent authorisation decisions at runtime.
At this point I was checking that downstream services would receive the role and context they needed to make access decisions reliably.
Beyond the initial setup, the project was designed with day-to-day maintainability in mind. That meant keeping the Keycloak configuration clear, making role assignments predictable, and structuring clients and groups in a way that would still make sense as more services and users were added.
That matters because IAM systems tend to become harder to reason about over time unless the structure is kept simple and consistent from the start.
This project gave me a practical way to design and test a Keycloak-based IAM setup across multiple services, with a strong focus on keeping authentication reliable, access control clear, and the overall model maintainable as the environment grows.