In the end I took the auth token from the admin client and did a PUT request via the python requests library:
# Add Organization as a custom user profile attribute against the realm
headers = {
'accept': 'application/json, text/plain, */*',
'authorization': f'Bearer {admin.connection.token["access_token"]}',
'content-type': 'application/json'
}
url = f'http://keycloak:8080/admin/realms/{REALM_NAME}/users/profile'
data = {
'attributes': [
{
'name': 'username',
'displayName': '${username}',
'validations': {
'length': {
'min': 3,
'max': 255,
},
'username-prohibited-characters': {},
'up-username-not-idn-homograph': {},
},
'permissions': {
'view': ['admin', 'user'],
'edit': ['admin', 'user'],
},
'multivalued': False,
},
{
'name': 'email',
'displayName': '${email}',
'validations': {
'email': {},
'length': {
'max': 255,
},
},
'required': {
'roles': ['user'],
},
'permissions': {
'view': ['admin', 'user'],
'edit': ['admin', 'user'],
},
'multivalued': False,
}, {
'name': 'firstName',
'displayName': '${firstName}',
'validations': {
'length': {
'max': 255,
},
'person-name-prohibited-characters': {},
},
'required': {
'roles': ['user'],
},
'permissions': {
'view': ['admin', 'user'],
'edit': ['admin', 'user'],
},
'multivalued': False,
},
{
'name': 'lastName',
'displayName': '${lastName}',
'validations': {
'length': {
'max': 255,
},
'person-name-prohibited-characters': {},
},
'required': {
'roles': ['user'],
},
'permissions': {
'view': ['admin', 'user'],
'edit': ['admin', 'user'],
},
'multivalued': False},
{
'name': 'organization',
'displayName': 'Organization',
'required': {
'roles': ['admin', 'user'],
},
'permissions': {
'edit': ['admin'],
'view': ['user', 'admin'],
},
'multivalued': False,
'annotations': {},
'validations': {
'length': {
'min': '1',
'max': '255',
},
},
},
],
'groups': [
{
'name': 'user-metadata',
'displayHeader': 'User metadata',
'displayDescription': 'Attributes, which refer to user metadata',
},
],
}
response = requests.put(url, headers=headers, json=data)
if response.status_code != 200:
print('Could not update user profile attributes', response.status_code)
else:
print('Updated user profile attributes')