/**
* ING IAM — centralized identity & access console, frontend core
* @author Roshan Aryan Majhi · top contributor by volume
*/
One identity.
Every tenant.
ING IAM is the access plane for ING applications: Keycloak SSO at the gate, then a multi-tenant RBAC console where admins map applications → tenants → roles → permission groups, audit every change, and issue API tokens. I am its top contributor by commit volume on a small team.
// design_system
System first, screens second.
color/tokens
primary
#EA580C
success
#0C9D61
info
#2F6FED
warning
#F59E0B
error
#DC2626
border
#E4E4E7
type/scale
Aa
Inter Variable / Geist
Heading 20
Body 14 · tracking-tight
mono 11 · tables & tokens
radius/0.625rem
buttons lg · badges full
components/ui
{ "application": "attendease", "tenant": "everest-campus", "role": "role_student", "permissions": ["attendance.read"] }
| Role | users.write | roles.assign | tokens.issue |
|---|---|---|---|
| admin | |||
| developer | |||
| viewer |
view all →
// unauthenticated → IdP login <ProtectedRoute> <RoleGuard allowedRoles={["admin"]}> <Layout /> </RoleGuard> </ProtectedRoute>
// key factory per domain GET_USERS: (params) => ["get", "users", params]; // refetch all list variants invalidate(GET_USERS_PREFIX);
+22 more in package.json
toggle to compare
iam/role-access?app=attendease&tenant=3&tab=roles
opens the exact filters, for anyone with access
// why_it_exists
Every app needs auth. None should own it.
Without a central IAM, each product re-implements login, roles and permissions — drift, duplicated admin screens, and access reviews done in spreadsheets.
ING IAM centralizes that. Identity in Keycloak, authorization in one console: applications register once, tenants scope them, roles bundle permission groups, and every grant is auditable. Products ask who-can-what — the IAM answers.
// feature_modules
What ships inside.
sso_auth_gate
Keycloak SSO via keycloak-js (check-sso), protected routes that bounce unauthenticated users to the IdP login, and role guards that redirect per role — superadmin, admin, developer.
role_access_matrix
The heart of the console. Pick an application + tenant, then map roles↔permissions in both directions — roles-to-permissions and permissions-to-roles — with indeterminate states, select-all, and scoped search.
tenant_mappings
Tenant-role and tenant-permission mapping screens bind identities to their scope: which tenants an application sees, which roles and permission groups each tenant carries.
identity_crud
Full lifecycle for applications, tenants (with logo upload + size validation), users, students, admins, roles and permission groups — tables, dialogs, soft delete / restore, status toggles.
global_search
A cmdk command-palette search across the whole IAM graph with per-application indicators, loading and empty states, resetting on navigation and dialog close.
audit_and_tokens
Activity logs with detail dialogs (actor, subject, diff grid), plus personal access token management — issue, list with creator column, and revoke.
data_layer
TanStack Query throughout with a central key factory per domain (prefix + params) so list variants invalidate in one call; axios instance with refresh handling; nuqs keeps filters in the URL.
// engineering_decisions
Worth noting.
- +Identity stays in Keycloak — the app never stores passwords — SSO login, refresh and redeem flow through the IdP, the console only models authorization on top.
- +Mappings are bidirectional — role→permissions for least-privilege reviews, permissions→roles for blast-radius checks — same data, two questions answered.
- +Query keys are a factory — GET_*_PREFIX plus params means one invalidate call refetches every filtered, sorted or paginated variant of a list.
- +Filters live in the URL — nuqs serializes table state so a filtered roles view is shareable and refresh-safe, same philosophy as the CRM build.
- +One table, every entity — a shared shadcn data-table (sorting, selection, pagination, column widths) renders applications through tokens — new entities get UI for free.
// my_role
What I built.
Top contributor by commit volume, owning global search, the role-access matrix, mapping guards and the QC polish pass across the console.
$global_search
- API integration for cross-entity search with per-application indicators
- Loading, empty-state and scoped search (incl. disabled search on mapping screens)
- Reset-on-navigate, dialog permission viewer, hover and UX fixes
$role_access_matrix
- Scoped permission display per tenant in roles→permissions views
- Permission-group fetch by role id, edit-table fixes, toast migration to custom toasts
- Tenants column for roles→permissions and permission listings
$mappings_and_guards
- Disabled-state fixes for roles in tenant-role mapping
- Unauthorized-path navigation guard (typing a path no longer leaks pages)
- Table-height, sidebar scroll and collapse-mode fixes across viewports
$qc_and_polish
- QC pass: nav colors, cancel/create-another buttons, user-create route, activity subject descriptions
- Tenant column-width and permission-scoping fixes
- Font, hover and layout polish across topbar, sidebar and dialogs
// in_one_line
A single access plane where SSO is the gate and a bidirectional matrix is the map — every grant scoped, searchable and auditable.