Skip to content

Custom Required Actions cannot be removed via PUT /admin/realms/{realm}/users/{id} #48144

Description

@sebastianandress

Before reporting an issue

  • I have read and understood the above terms for submitting issues, and I understand that my issue may be closed without action if I do not follow them.

Area

admin/api

Describe the bug

When updating a user's requiredActions via PUT /admin/realms/{realm}/users/{id}, built-in required actions (members of the UserModel.RequiredAction enum, e.g. UPDATE_PASSWORD, VERIFY_EMAIL) are correctly added and removed. However, custom required actions (registered via the Required Action SPI) are silently ignored when removed from the list.

Adding a custom required action via the same endpoint works correctly.

Version

26.0.1

Regression

  • The issue is a regression

Expected behavior

PUT with requiredActions: [] (or any list that omits MY_CUSTOM_ACTION) should remove the custom action from the user. No error is indicated, but the action is not removed.

Actual behavior

The custom required action remains on the user after the PUT. Built-in actions (e.g. UPDATE_PASSWORD) in the same list are removed correctly.

How to Reproduce?

import requests

KEYCLOAK_URL = "http://localhost:8080"
REALM        = "master"
TOKEN        = "<admin-token>"

HEADERS = {
    "Authorization": f"Bearer {TOKEN}",
    "Content-Type": "application/json",
}

# 1. Find a user
users = requests.get(
    f"{KEYCLOAK_URL}/admin/realms/{REALM}/users?max=1",
    headers=HEADERS,
).json()
user = users[0]
uid  = user["id"]

# 2. Add a custom required action
user["requiredActions"] = ["MY_CUSTOM_ACTION"]
requests.put(f"{KEYCLOAK_URL}/admin/realms/{REALM}/users/{uid}", json=user, headers=HEADERS)

# Verify: action is present
user = requests.get(f"{KEYCLOAK_URL}/admin/realms/{REALM}/users/{uid}", headers=HEADERS).json()
print(user["requiredActions"])  # → ['MY_CUSTOM_ACTION']  ✓

# 3. Remove the custom required action
user["requiredActions"] = []
resp = requests.put(f"{KEYCLOAK_URL}/admin/realms/{REALM}/users/{uid}", json=user, headers=HEADERS)
print(resp.status_code)  # → 204  (no error)

# Verify: action is still present — BUG
user = requests.get(f"{KEYCLOAK_URL}/admin/realms/{REALM}/users/{uid}", headers=HEADERS).json()
print(user["requiredActions"])  # → ['MY_CUSTOM_ACTION']  ✗ (expected: [])

Anything else?

Environment
Keycloak version: 26.0.1
Deployment: Docker / standalone
Custom required action registered via `RequiredActionProvider SPI

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions