Authorization Model
The Voltimax IoT Platform uses Keycloak's resource-based authorization model. This page explains how resources, scopes, policies, and permissions are structured to control access.
Overview
Authorization decisions follow a layered model:
- A user is assigned one or more client roles
- Policies reference roles to define access rules
- Permissions bind a resource + scope to one or more policies
- When an API endpoint requires access to a resource with a specific scope, Keycloak evaluates the relevant permission and its associated policies
Resources
Resources represent domain entities in the platform. Each resource has a name, a URN-style type identifier, and a set of applicable scopes (e.g. read, write, delete). Not all resources support all scopes - for example, solar-forecast only supports read because forecast data is sourced externally.
Resources are defined in KeycloakRealmConfiguration.GetAuthorizationResources(). The current set of resources and their scopes can be inspected in that file or via the Keycloak admin console under the iot-platform-api client's Authorization tab.
Policies
Policies are the rules Keycloak evaluates to determine access. The platform uses role-based policies - each policy checks whether the authenticated user holds a specific client role (e.g. platform-admin-policy checks for the platform-admin role).
Each policy is of type role and uses UNANIMOUS decision strategy, meaning the role must be present for the policy to grant access. Policies are defined in KeycloakRealmConfiguration.GetAuthorizationPolicies().
Policy representation
In Keycloak's model, policies are configured with their role reference in the Config.AdditionalData["roles"] property as a JSON-serialized array:
[{ "id": "iot-platform-api/platform-admin", "required": true }]The role ID format is {clientId}/{roleName}, and required: true means the role must be directly assigned (not inherited).
Permissions
Permissions link resources and scopes to policies. They are of type scope and use AFFIRMATIVE decision strategy - if any associated policy grants access, the permission is satisfied.
A permission is a resource:scope pair. In code, it's represented as:
new Permission("gateways", "read") // PolicyName = "gateways:read"In Keycloak, this maps to a scope permission named gateways-read that binds the gateways resource with the read scope to one or more role-based policies.
All permission constants are defined in Permissions.cs and can be enumerated via Permissions.All. The complete set of permission-to-role mappings is visible in the Keycloak admin console or in KeycloakRealmConfiguration.
Decision Strategies
Two decision strategies are used:
- UNANIMOUS (role policies): All conditions must pass. Since each role policy checks a single role, this simply means "the user must have this role."
- AFFIRMATIVE (scope permissions): At least one associated policy must grant access. This means a user with any of the listed roles gets access.
Source Files
The authorization model is implemented across two projects:
Voltimax.Platform.Api/Core/Authorization/-Permissiontype,Permissionsconstants,RequirePermission()extensions, and authorization setupVoltimax.MigrationService/Keycloak/-KeycloakRealmConfiguration(resource/scope/policy definitions) andKeycloakAuthorizationManager(Admin API import)
Adding New Resources
See Provisioning for the end-to-end workflow for adding a new protected resource and permission.