Appearance
Authentication Flow
End-to-end authentication and authorisation flow for the Microtec ERP platform.
Protocol: OpenID Connect (OIDC) / OAuth2
Identity Provider: Keycloak 22 with custom SPIs
Realms:microtec(ERP users) ·businessowner(tenant admins)
Overview
Microtec ERP uses a dual-token architecture:
- Keycloak JWT — issued by Keycloak, validates the user's identity and Keycloak-level roles
- ERP Access Context Token — generated by the ERP backend after validating the Keycloak JWT; contains ERP-specific claims (tenant ID, permissions, subscription features)
The Gateway validates only the Keycloak JWT. Individual microservices exchange it for (or validate against) the ERP Access Context Token stored in Redis.
Authentication Sequence — Browser Login
Token Refresh Flow
Logout Flow
[INFO] Backchannel logout is pre-configured by the
keycloak-seedingSPI. Each service's logout URL is set to{service-internal-url}/auth/logout.
ERP Access Context Token
The ERP Access Context Token is not a JWT — it is a Redis-stored session object serialised as JSON. It contains:
json
{
"userId": "uuid",
"tenantId": "uuid",
"tenantSlug": "my-company",
"databaseName": "Microtec_MyCompany",
"subscriptionTier": "Enterprise",
"enabledModules": ["Accounting", "Inventory", "HR"],
"permissions": [
"invoices:read",
"invoices:write",
"reports:export"
],
"features": {
"maxUsers": 500,
"zatcaEnabled": true,
"multiWarehouse": true
},
"expiresAt": "2026-05-30T12:00:00Z"
}This context is resolved per-request by ITenantContextManager and is used to:
- Route EF Core queries to the correct tenant database
- Enforce feature-level authorisation (
[RequireFeature("zatcaEnabled")]) - Apply row-level security via EF global query filters
Authentication Flow — Keycloak Custom SPIs
Flow priority correction (keycloak-seeding SPI)
The seeding SPI sets flow priorities on every Keycloak startup:
csharp
// KeycloakProviders/src/...
var flowPriorities = new Dictionary<string, int>
{
{ "mac-auth-flow", 10 },
{ "cookie-auth-flow", 20 },
{ "idp-redirect-flow", 30 },
{ "forms-auth-flow", 40 }
};[WARNING] If priorities are wrong (e.g., due to a Keycloak upgrade resetting them), restart Keycloak — the seeding SPI restores correct priorities on startup.
Multi-Realm Architecture
Token Claims Reference
Keycloak JWT (access token) — key claims
| Claim | Description | Example |
|---|---|---|
sub | User UUID | 3bb564df-0f24-4ea6-... |
preferred_username | Username | ahmed@company.com |
realm_access.roles | Keycloak realm roles | ["erp-user", "accounting-admin"] |
resource_access | Client-specific roles | {"apps-portal": {"roles": ["user"]}} |
tenant_id | Custom claim — tenant UUID | abc123 |
exp | Token expiry (Unix timestamp) | 1748649600 |
iss | Issuer | https://domain/auth/realms/microtec |
Custom claim tenant_id
Injected by the Keycloak seeding SPI via a custom protocol mapper. The backend uses this claim to resolve the tenant context without an extra database lookup.
Security Considerations
- Token storage: Keycloak-js stores tokens in memory only — never in
localStorageorsessionStorage(XSS protection) - PKCE: Enabled for all public OIDC clients (code flow with PKCE, no client secret in browser)
- Token lifetime: Access token = 5 minutes; Refresh token = 30 minutes (configurable per realm)
- Brute force protection: Enabled in Keycloak realm settings — 5 failed attempts → 15-minute lockout
- mTLS on Private CAE: All service-to-service traffic inside the private CAE is encrypted and mutually authenticated
Related Documentation
- Service Topology — where each auth component lives
- Keycloak Realm Recovery Runbook
- Security Guidelines
- Keycloak Providers Source