User Profile Unmanaged Attribute Policy
When configuring Keycloak user profiles, the unmanagedAttributePolicy setting controls how the system handles user attributes that aren't explicitly defined in the user profile configuration. Understanding how to properly configure this policy is essential for managing custom user attributes and controlling attribute permissions.
Related issues: #1016
The Problem
Users often encounter challenges when configuring user profile unmanaged attribute policies because:
- Setting unmanagedAttributePolicy directly at the top level doesn't work as expected
- The correct location for this setting within the user profile configuration is unclear
- Different Keycloak versions have different user profile configuration structures
- Error messages don't clearly indicate where the policy should be placed
- The relationship between managed and unmanaged attributes is not well documented
- Understanding the impact of different policy values requires trial and error
What is unmanagedAttributePolicy?
The unmanagedAttributePolicy determines how Keycloak handles user attributes that are NOT explicitly defined in the user profile configuration. These are attributes that users or administrators might add outside the defined profile schema.
Policy Values:
| Value | Behavior | Use Case |
|---|---|---|
ENABLED |
Unmanaged attributes can be created and edited by users | Allow custom user attributes freely |
ADMIN_EDIT |
Only admins can create/edit unmanaged attributes | Restrict attribute creation to admins |
ADMIN_VIEW |
Only admins can view unmanaged attributes; users cannot | Hide custom attributes from users |
Correct Configuration Location
The Wrong Way (Common Mistake)
This DOES NOT work:
realm: "myrealm"
userProfile:
unmanagedAttributePolicy: "ENABLED" # ❌ Wrong location!
attributes:
- name: "username"
required: true
Why it fails: The unmanagedAttributePolicy is not a direct child of userProfile. It must be nested within the profile configuration structure.
The Correct Way
This WORKS:
realm: "myrealm"
userProfile:
attributes:
- name: "username"
displayName: "${username}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
validations: {}
- name: "email"
displayName: "${email}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
validations:
email: {}
- name: "firstName"
displayName: "${firstName}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
- name: "lastName"
displayName: "${lastName}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
groups: []
unmanagedAttributePolicy: "ENABLED" # ✅ Correct location!
Key points:
- unmanagedAttributePolicy is at the same level as attributes and groups
- It's inside userProfile but not inside attributes
- All managed attributes should be explicitly defined before setting the policy
Usage
Allow Users to Add Custom Attributes
Scenario: You want users to be able to add their own custom attributes (like department, phone extension, etc.)
realm: "myrealm"
userProfile:
attributes:
- name: "username"
displayName: "${username}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
- name: "email"
displayName: "${email}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
validations:
email: {}
unmanagedAttributePolicy: "ENABLED"
Result: - Users can add custom attributes via API or account management - Users can view and edit their own custom attributes - Admins can also view and edit all attributes - Useful for flexible, self-service attribute management
Example of user adding custom attribute:
{
"username": "john.doe",
"email": "john@example.com",
"attributes": {
"department": ["Engineering"],
"phone_extension": ["1234"]
}
}
Restrict Unmanaged Attributes to Admin Only (Edit)
Scenario: Only administrators should be able to create and modify unmanaged attributes.
realm: "myrealm"
userProfile:
attributes:
- name: "username"
displayName: "${username}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
- name: "email"
displayName: "${email}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
validations:
email: {}
- name: "firstName"
displayName: "${firstName}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
- name: "lastName"
displayName: "${lastName}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
unmanagedAttributePolicy: "ADMIN_EDIT"
Result: - Users can view unmanaged attributes but cannot create or edit them - Only admins can create, view, and edit unmanaged attributes - Useful for controlled attribute management with admin oversight
Hide Unmanaged Attributes from Users
Scenario: Unmanaged attributes should be completely hidden from regular users.
realm: "myrealm"
userProfile:
attributes:
- name: "username"
displayName: "${username}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
- name: "email"
displayName: "${email}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
validations:
email: {}
unmanagedAttributePolicy: "ADMIN_VIEW"
Result: - Users cannot view, create, or edit unmanaged attributes - Only admins can see and manage all attributes - Useful for storing sensitive or system-level attributes - Users only see attributes explicitly defined with user view permissions
Complete User Profile Configuration Example
Scenario: A corporate environment with defined attributes and controlled unmanaged attribute access.
realm: "corporate"
userProfile:
attributes:
# Standard Keycloak attributes
- name: "username"
displayName: "${username}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin"] # Only admin can change username
validations:
length:
min: 3
max: 255
username-prohibited-characters: {}
- name: "email"
displayName: "${email}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
validations:
email: {}
length:
max: 255
- name: "firstName"
displayName: "${firstName}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
validations:
length:
max: 255
person-name-prohibited-characters: {}
- name: "lastName"
displayName: "${lastName}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
validations:
length:
max: 255
person-name-prohibited-characters: {}
# Custom managed attributes
- name: "department"
displayName: "Department"
required: false
permissions:
view: ["admin", "user"]
edit: ["admin"] # Only admin can set department
validations:
length:
max: 100
- name: "employeeId"
displayName: "Employee ID"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin"] # Only admin can set employee ID
validations:
length:
min: 5
max: 20
- name: "phoneNumber"
displayName: "Phone Number"
required: false
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
validations:
pattern:
pattern: "^\\+?[1-9]\\d{1,14}$"
error-message: "Invalid phone number format"
groups: []
unmanagedAttributePolicy: "ADMIN_EDIT"
This configuration: - Defines 6 managed attributes with clear permissions - Allows admins to add additional attributes as needed - Prevents users from adding arbitrary attributes - Enforces validation on all managed attributes - Provides clear separation between user-editable and admin-only fields
Attribute Types: Managed vs Unmanaged
Managed Attributes
Definition: Explicitly defined in the attributes array with:
- Name
- Display name
- Permissions
- Validations
- Required flag
Example:
attributes:
- name: "department"
displayName: "Department"
required: false
permissions:
view: ["admin", "user"]
edit: ["admin"]
Characteristics: - Full control over permissions - Validation rules enforced - Clear documentation in configuration - Consistent behavior across the realm
Unmanaged Attributes
Definition: Attributes NOT in the attributes array, added dynamically by users or systems.
Examples:
- custom_field_1
- legacy_system_id
- temporary_flag
Behavior: Controlled by unmanagedAttributePolicy
When to use: - Temporary attributes during migrations - Integration with external systems - User-defined custom fields - Attributes that vary per user type
Common Pitfalls
1. Wrong Configuration Level
Problem:
realm: "myrealm"
unmanagedAttributePolicy: "ENABLED" # ❌ At realm level
userProfile:
attributes:
- name: "username"
Solution:
realm: "myrealm"
userProfile:
attributes:
- name: "username"
unmanagedAttributePolicy: "ENABLED" # ✅ Inside userProfile
2. Missing Required Attributes
Problem:
Solution: Always include standard Keycloak attributes:
userProfile:
attributes:
- name: "username"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
- name: "email"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
unmanagedAttributePolicy: "ENABLED"
3. Incomplete Attribute Definitions
Problem:
What happens: Attribute behavior is unpredictable.
Solution: Always include complete attribute definitions:
attributes:
- name: "department"
displayName: "Department"
required: false
permissions:
view: ["admin", "user"]
edit: ["admin"]
validations: {}
4. Conflicting Policies and Permissions
Problem:
userProfile:
attributes:
- name: "customField"
permissions:
edit: ["user"] # Users can edit
unmanagedAttributePolicy: "ADMIN_EDIT" # But unmanaged attributes are admin-only
Confusion: If customField is managed, users can edit it. But if it becomes unmanaged (removed from config), only admins can edit.
Solution: Be consistent with your policy:
- If allowing user attributes, use ENABLED
- If restricting to admins, define all needed attributes as managed
5. Exporting and Re-importing User Profiles
Problem: Exporting a realm and attempting to re-import the user profile without proper structure.
Exported (may be incomplete):
Solution: Ensure unmanagedAttributePolicy is included:
Best Practices
- Always Define Core Attributes: Include username, email, firstName, lastName as managed attributes
- Use Managed Attributes for Important Fields: Define critical business attributes explicitly
- Choose Policy Based on Security: Use
ADMIN_EDITorADMIN_VIEWfor production environments - Document Custom Attributes: Comment your configuration explaining custom fields
- Test Permission Changes: Verify users can/cannot edit attributes as expected
- Version Control User Profiles: Track changes to user profile configuration in Git
- Validate After Import: Check Admin Console to verify policy was applied correctly
- Consider Migration Impact: Changing policy affects existing unmanaged attributes
Validation and Permissions Reference
Permission Values
| Permission | Who Can Access |
|---|---|
["admin", "user"] |
Both admins and users |
["admin"] |
Only admins |
["user"] |
Only users (rare, usually combined with admin) |
Common Validations
validations:
# Email format
email: {}
# String length
length:
min: 3
max: 255
# Pattern matching
pattern:
pattern: "^[A-Z]{2}\\d{4}$"
error-message: "Must be 2 letters + 4 digits"
# Username restrictions
username-prohibited-characters: {}
# Person name restrictions
person-name-prohibited-characters: {}
Migration Scenarios
From No User Profile to Managed Profile
Step 1: Export current user attributes
Step 2: Create user profile configuration
realm: "myrealm"
userProfile:
attributes:
# Standard attributes
- name: "username"
displayName: "${username}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
- name: "email"
displayName: "${email}"
required: true
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
validations:
email: {}
# Existing custom attributes (now managed)
- name: "department"
displayName: "Department"
required: false
permissions:
view: ["admin", "user"]
edit: ["admin"]
- name: "employeeId"
displayName: "Employee ID"
required: false
permissions:
view: ["admin", "user"]
edit: ["admin"]
unmanagedAttributePolicy: "ADMIN_EDIT" # Lock down future attributes
Step 3: Import configuration
java -jar keycloak-config-cli.jar \
--keycloak.url=http://localhost:8080 \
--keycloak.user=admin \
--keycloak.password=admin \
--import.files.locations=user-profile-config.yaml
Step 4: Verify in Admin Console
- Navigate to: Realm Settings → User Profile
- Check that all attributes are defined
- Verify unmanagedAttributePolicy is set correctly
Changing Policy from ENABLED to ADMIN_EDIT
Scenario: You've allowed users to create custom attributes, now you want to lock it down.
Current:
New:
userProfile:
attributes:
# Add any commonly used unmanaged attributes as managed
- name: "phoneExtension" # Was unmanaged, now managed
displayName: "Phone Extension"
required: false
permissions:
view: ["admin", "user"]
edit: ["admin", "user"]
- name: "officeLocation" # Was unmanaged, now managed
displayName: "Office Location"
required: false
permissions:
view: ["admin", "user"]
edit: ["admin"]
unmanagedAttributePolicy: "ADMIN_EDIT" # Changed
Impact: - Existing unmanaged attributes remain but become read-only for users - Users cannot create new unmanaged attributes - Any frequently used unmanaged attributes should be promoted to managed
Troubleshooting
Policy Not Applied
Symptom: Users can still edit unmanaged attributes despite ADMIN_EDIT setting
Diagnosis:
# Check current user profile via API
curl -s "http://localhost:8080/admin/realms/myrealm/users/profile" \
-H "Authorization: Bearer $TOKEN" | jq '.unmanagedAttributePolicy'
Possible causes: 1. Policy not at correct level in configuration 2. Configuration not imported successfully 3. Keycloak version doesn't support user profiles
Solution: - Verify configuration structure - Check import logs for errors - Ensure Keycloak version 15+ (user profiles introduced in v15)
Attribute Permissions Not Working
Symptom: Users can edit attributes marked as admin-only
Cause: Attribute is unmanaged and policy is ENABLED
Solution: Move attribute to managed attributes list:
attributes:
- name: "restrictedField"
permissions:
view: ["admin", "user"]
edit: ["admin"] # Now enforced
Cannot Create Users After Enabling Profile
Symptom: User creation fails after enabling user profile
Cause: Required attributes not provided during user creation
Solution: Ensure all required: true attributes are provided:
{
"username": "john.doe",
"email": "john@example.com",
"firstName": "John",
"lastName": "Doe",
"enabled": true
}
Or mark optional in profile:
Configuration Options
# Validate configuration before import
--import.validate=true
# Enable remote state management
--import.remote-state.enabled=true
Consequences
When configuring user profile unmanaged attribute policy:
- ENABLED Policy: Maximum flexibility but less control over data structure
- ADMIN_EDIT Policy: Balanced approach for most organizations
- ADMIN_VIEW Policy: Highest security but may hide useful information from users
- Managed Attributes Required: Standard attributes (username, email, etc.) must be explicitly defined
- Existing Attributes Unaffected: Changing policy doesn't remove existing unmanaged attributes
- Validation Only on Managed: Unmanaged attributes have no validation rules
Security Considerations
- Least Privilege: Use
ADMIN_EDITorADMIN_VIEWin production - Sensitive Data: Store sensitive attributes as managed with admin-only permissions
- Data Leakage:
ENABLEDpolicy allows users to add arbitrary data - Compliance: Some regulations require controlled attribute management
- Audit Trail: Managed attributes provide better audit capabilities
Keycloak Version Compatibility
| Keycloak Version | User Profile Support | unmanagedAttributePolicy |
|---|---|---|
| < 15.0.0 | No | N/A |
| 15.0.0 - 18.0.0 | Experimental | Limited |
| 19.0.0+ | Stable | Full support |
| 21.0.0+ | Enhanced | Recommended |
Note: For Keycloak versions before 15, user profile configuration is not available.