Resource Model
Summary
A Resource in Keymate represents any protected digital asset that requires authorization control. Resources can be REST API endpoints, files, database records, UI components, or any other system artifact. Keymate extends Keycloak's UMA 2.0 resource model with organizational metadata, lifecycle states, and classification capabilities through types, categories, and tags.
Why It Exists
Authorization systems need a structured way to represent "what" is being protected. Without a formal resource model:
- Inconsistent protection — Different teams model the same API differently
- No lifecycle tracking — No visibility into resource status (active, deprecated, inactive)
- Missing context — Authorization decisions lack environmental and ownership context
- Classification gaps — Resources cannot be grouped for bulk policy assignment
The Resource Model provides a standardized representation that enables consistent policy authoring, organizational classification, and lifecycle governance.
Where It Fits in Keymate
Resources belong to a Resource Server (a Keycloak Client with authorizationServicesEnabled=true). Each resource can have multiple Scopes defining permitted actions. Policies evaluate against resource-scope pairs to make authorization decisions.
Boundaries
This concept covers:
- Resource entity structure and metadata fields
- Resource Server relationship
- Type and Category classification
- Lifecycle states (ACTIVE, INACTIVE, DEPRECATED)
- URI pattern matching
- Tenant inheritance from Resource Server
This concept does not cover:
- Scope definitions → see Scope Model
- Policy authoring → see Policy Model
- Permission evaluation → see Authorization Models
How It Works
Resource Server Relationship
Every resource belongs to a Resource Server, which is a Keycloak Client configured with:
serviceAccountsEnabled = true— enables Client Credentials GrantauthorizationServicesEnabled = true— enables UMA 2.0 resource management
When a Resource Server is created with a tenantId, all resources under it inherit that tenant association. This provides automatic tenant isolation without per-resource configuration.
Resource Entity Structure
| Field | Type | Description |
|---|---|---|
id | UUID | Keycloak-generated resource identifier |
name | String | Unique identifier within Resource Server (e.g., /api/users/*) |
displayName | String | Human-readable name for admin UI and consent screens |
uris | Array of strings | URI patterns for request matching (supports wildcards) |
type | String | Free-text resource type (e.g., "API", "FILE") |
typeId | UUID | Reference to ResourceType entity for formalized classification |
categoryId | UUID | Reference to ResourceCategory for business domain grouping |
scopes | Array of strings | Actions permitted on this resource |
status | Enum | ACTIVE, INACTIVE, or DEPRECATED |
environment | Enum | DEV, TEST, or PROD |
owner | String | Team or person responsible for this resource |
tags | JSON Array | Flexible keyword labels for filtering |
ownerManagedAccess | Boolean | UMA 2.0 user-managed access flag |
Classification System
Keymate provides three complementary classification mechanisms:
Resource Type — What kind of resource is it?
- REST API, GraphQL API, gRPC Service, Database Table, File Storage, UI Component
- Standardized types enable type-based filtering and reporting
Resource Category — What business domain does it belong to?
- UI, UI_MENU_ITEM, DATA_OBJECT, URI
- Categories group resources by functional area
Tags — Flexible keyword labeling
["pci-compliant", "critical", "v2"]- Tags are auto-created when referenced — no pre-registration required
Lifecycle States
| Status | Behavior |
|---|---|
ACTIVE | Normal operation — authorization checks are performed |
INACTIVE | Temporarily disabled — all access denied (403 Forbidden) |
DEPRECATED | Marked for removal — new usage blocked, existing access may continue |
URI Pattern Matching
Resources use URI patterns for request matching at Policy Enforcement Points:
/api/users/* → Matches all paths under /api/users/
/api/users/{id} → Matches parameterized paths
/api/users/{id}/profile → Specific sub-resource
Multiple URIs can be assigned to a single resource to group related endpoints.
Diagram
Example Scenario
Scenario
A platform administrator creates a resource representing the payment transactions API, classifying it as a REST API in the UI category with PCI compliance tagging.
Input
- Actor: Platform administrator
- Resource Server:
payment-api(tenant: Acme Corp) - Action: Create resource
- Context:
{
"name": "/api/payments/transactions",
"displayName": "Payment Transactions API",
"uris": ["/api/payments/transactions", "/api/payments/transactions/*"],
"typeId": "type-rest-api-uuid",
"categoryId": "category-ui-uuid",
"scopes": ["read", "create", "refund"],
"status": "ACTIVE",
"environment": "PROD",
"owner": "payment-team@example.com",
"tags": ["pci-compliant", "critical", "sla-99.9"]
}
Expected Outcome
- Result: Resource created with Keycloak UUID and extension metadata
- Why: The resource is now available for policy assignment. Authorization requests to
/api/payments/transactions/*will match this resource, and policies can evaluate based on its scopes, type, category, tags, and tenant association.
Common Misunderstandings
-
"Resources are the same as permissions" — Resources represent what is protected; permissions combine resources, scopes, and policies to determine who can access what.
-
"Each endpoint needs its own resource" — URI wildcards (
/api/users/*) allow grouping related endpoints under a single resource. Create separate resources only when different scopes or policies apply. -
"Status INACTIVE deletes the resource" — INACTIVE is a soft-disable; the resource remains in storage but authorization checks fail. Use DELETE to permanently remove.
Resources inherit tenant association from their Resource Server. You cannot assign a resource to a different tenant than its parent Resource Server.
Design Notes / Best Practices
-
Use URI-based naming for API resources (e.g.,
/api/orders/{id}) to enable clear request-to-resource mapping at enforcement points. -
Prefer wildcards over many resources when the same scopes and policies apply.
/api/users/*is cleaner than separate resources for/api/users/list,/api/users/create, etc. -
Tag for cross-cutting concerns — Use tags like
pci-compliant,gdpr-relevant, orrate-limitedfor attributes that span multiple types and categories. -
Lifecycle resources through environments — Create resources in DEV first, promote to TEST, then PROD. Use environment filtering for deployment-specific views.
Auto-created tags simplify onboarding. Reference any tag in a resource creation request — if it does not exist, Keymate creates it automatically.
Related Use Cases
- Defining API resources for microservice authorization
- Classifying UI components for menu-level access control
- Tagging resources for compliance reporting
- Implementing multi-tenant resource isolation
Related Docs
Scope Model
Actions permitted on resources
Authorization Models
RBAC, ABAC, ReBAC concepts
OpenAPI Import
Auto-discover resources from API specs
Policy Model
Define who can access resources
FAQ
Can a resource belong to multiple Resource Servers?
No. Each resource belongs to exactly one Resource Server. If the same logical resource needs different policies in different contexts, create separate resources in each Resource Server.
How do I migrate resources between environments?
Export the resource definition from the source environment, update the environment field, and import into the target Resource Server. The resource ID will be newly generated in the target.
What happens to policies when I deprecate a resource?
Policies referencing the resource remain intact but no longer match requests. Review and update policies before or after deprecation to avoid unexpected authorization failures.
Can I use regex in URI patterns?
Keycloak supports simple wildcards (*) and path parameters ({id}), not full regex. For complex matching, use multiple URIs or implement custom matching logic at the enforcement point.