Authentication and Authorization Architecture
Lana separates authentication from application authorization:
- Keycloak issues OIDC access tokens and owns login sessions.
- Rust API servers validate token signatures, expiry, audience, and realm issuer.
- Lana identity claims link the token to an application subject.
- Casbin evaluates the subject's application permissions.
- The use-case audit layer records authorization decisions and request metadata according to the action's audit policy.
Realms and Clients
Realm names are instance-specific and can be overridden. The local stack uses:
| Realm | Purpose | Frontend client |
|---|---|---|
main-internal | Administrative users | admin-panel |
main-customer | Bank customers | External customer clients, including the optional mobile demo |
main-partner | Partner users | partner-portal |
tf/modules/keycloak-realms/ defines the realms, clients, protocol mappers, and authentication flows. Backend service accounts manage Keycloak users using federated client authentication; they are not a generic GraphQL api-client.
Local passwordless DEV browser/direct-grant flows are a development convenience. Deployments outside local development must disable them. See Authentication (Local Dev).
Backend Token Validation
The API config nests the Keycloak connection under each server. For example:
admin_server:
aud: admin-panel
keycloak:
internal_url: http://keycloak:8080/
public_url: https://keycloak.example.com/
realm: main-internal
customer_server:
aud: customer-portal
keycloak:
internal_url: http://keycloak:8080/
public_url: https://keycloak.example.com/
realm: main-customer
The JWKS URL is derived from internal_url and realm; the expected issuer is derived from public_url and realm. There are no top-level jwks_url or keycloak_issuer_url fields in these server configs. Set the public URL to the origin Keycloak uses in the token's iss, even if the server reaches Keycloak through an internal address.
JWT authentication requires these UUID-valued application identity claims; the admin and customer APIs additionally require a Keycloak sub:
| API | Claims |
|---|---|
| Admin | userId |
| Customer | partyId |
| Partner | partnerUserId, partnerId |
The application subject is not simply Keycloak's sub or a Keycloak realm role. A token must reference provisioned Lana entities, and those entities must be authorized for the requested operation.
The partner API also supports revocable partner API keys for unattended integrations. Those requests authenticate a partner-scoped API-key subject rather than a Keycloak user; see API Authentication.
Role-Based Access Control
Administrative access follows this relationship:
User → Role → Permission sets → Object/action permissions
An admin user has one current role, which can contain multiple permission sets. The seeded bank roles are superuser, admin, bank-manager, and accountant; they are not a hard-coded inheritance tree of teller and credit-officer roles. Custom roles can combine grantable permission sets. The bootstrap-configured superuser has additional protections against reassignment and permission removal.
Policies are persisted in PostgreSQL and evaluated by lib/use-case's Casbin integration. The model uses transitive role grouping and keyMatch object matching. Authorization is enforced by the application/use-case layer, not by a GraphQL RoleGuard annotation.
See Authorization (RBAC) for the model and permission sets. The authoritative seeded permission lists are in lana/app/src/authorization/seed.rs.
Audit Access
The admin API exposes authorization audit entries through audit:
query AuthorizationAudits {
audit(first: 10, authorized: false) {
edges {
node {
auditEntryId
recordedAt
object
action
authorized
requestIp
userAgent
}
}
}
}
Audit access itself requires the appropriate permission. See Audit System for storage and audit policies.
Sessions and Token Handling
The shared realm module configures 5-minute access tokens, a 24-hour SSO idle timeout, and refresh-token rotation. Other session limits remain dependent on realm/client configuration; the module does not guarantee a separate 30-minute refresh-token lifetime or an 8-hour session.
The admin panel uses keycloak-js with PKCE and refreshes tokens through its auth helper. Browser tokens should stay in memory; confidential-client secrets must not be embedded in a SPA. Logout clears the client session and redirects through Keycloak.
For client integration and token refresh examples, see API Authentication.