User management is one of those areas that looks simple from the outside: login, logout, create users, assign roles. But once an application grows beyond a single service, identity becomes a core platform concern.

I wanted to design and build a practical user management solution that follows modern engineering patterns: centralized authentication, role-based access control, protected APIs, clean admin workflows, and a frontend that only shows what the user is allowed to access.

That is how AuthCore was built.

AuthCore is a proof-of-concept identity and access management platform using:

  • Keycloak for authentication and identity
  • PostgreSQL as Keycloak’s persistent database
  • React for the user interface
  • NestJS for the backend user management API
  • JWT + JWKS for token validation
  • RBAC for protected endpoint access
  • Swagger for backend API exploration

Why Keycloak?

Instead of building authentication from scratch or cloud native solution, I used Keycloak as the identity provider.

Keycloak handles the heavy lifting:

  • Login and logout
  • OIDC Authorization Code Flow with PKCE
  • JWT access token generation
  • Realm roles
  • User identity storage
  • Admin APIs for user and role management

This keeps the application focused on business logic while Keycloak manages authentication in a standards-based way.

High-Level Architecture

The system follows a common industry pattern:

This design also works well for future microservices. Each service can independently validate the same Keycloak-issued JWT and enforce its own role requirements.

Authentication Flow

The React app does not directly handle passwords. Instead, it redirects users to Keycloak.

This keeps credentials away from the frontend application and follows modern OIDC best practices for SPAs using PKCE.

AuthCore uses realm roles from Keycloak to control access.

Example protected endpoints:

/v1/samples/profile-data
Required role: sample:profile-data
/v1/samples/admin-report
Required role: sample:admin-report

In the NestJS backend, protected routes use guards and decorators. The JWT strategy validates the token, and the role guard checks whether the token contains the required role.

Request comes in
-> JWT strategy validates token signature and issuer
-> user roles are extracted from token claims
-> role guard checks required endpoint role
-> request is allowed or rejected

If the user does not have access, the API returns 403 Forbidden

Admin User Management

The admin UI provides user management capabilities such as:

  • Viewing users
  • Creating users
  • Updating user details
  • Deleting users
  • Creating roles
  • Assigning roles
  • Granting access to protected services

A key requirement was that users should only see what they are allowed to access. So the frontend filters menus, services, and protected sample cards based on the user’s assigned roles.

For example, if a user does not have access to the Admin Report service, that service should not appear in their dashboard.

This improves both security posture and user experience.

PostgreSQL-Backed Keycloak

For persistence, Keycloak was configured with PostgreSQL instead of relying on temporary or volume-only local state.

The local Docker Compose setup includes:

keycloak-db
-> PostgreSQL database for Keycloak
keycloak
-> imports the AuthCore realm
-> connects to PostgreSQL
-> persists users, roles, sessions, and realm configuration

Swagger for API Exploration

The backend also exposes Swagger documentation at:

http://localhost:3001/docs

Swagger includes Bearer token support, so protected APIs can be tested by pasting a Keycloak access token into the Authorize dialog.

This makes development and debugging much easier.

Why This Design Is Industry-Aligned

The design follows several common enterprise and platform engineering principles:

  • Authentication is delegated to a dedicated identity provider
  • The frontend uses OIDC + PKCE instead of handling passwords directly
  • APIs validate JWTs using JWKS
  • Authorization is enforced server-side
  • RBAC is role-driven and centralized through Keycloak
  • Admin workflows manage access without code changes
  • Protected services are hidden in the UI when users lack access
  • The design can scale toward multiple independently deployed microservices

In a future microservice architecture, each service can use the same pattern:

Service A
-> validates JWT from Keycloak
-> checks Service A roles
Service B
-> validates JWT from Keycloak
-> checks Service B roles

This avoids coupling every service directly to the user management backend.

What I Would Add for Production

This POC already demonstrates a strong foundation, but a production-grade version would add:

  • HTTPS everywhere
  • Strong secret management
  • Audit logging
  • Token lifetime tuning
  • Refresh token hardening
  • Rate limiting by user and route
  • CI/CD security scanning
  • Monitoring and alerting
  • Infrastructure-as-code for complete Kubernetes solution
  • Backup and restore strategy for Keycloak PostgreSQL
  • Environment-specific Keycloak realms or clients

Final Thoughts

AuthCore shows how a modern user management platform can be built without reinventing authentication from scratch.

By combining Keycloak, React, NestJS, PostgreSQL, JWT validation, and RBAC, the system provides a clean foundation for secure user management and protected service access.

The most important design decision was separating responsibilities:

Keycloak handles identity.
NestJS enforces API access.
React reflects user permissions.
Roles connect everything.

That separation is what makes the design scalable, understandable, and ready to evolve toward a real microservice platform.

To know more about this refer my github: https://github.com/automationcalling/IDENTITY-HUB

Leave a comment

Trending