User Schema
ZITADEL allows you to define schemas for users, based on the JSON Schema Standard. This gives you the possibility to define your own data models for your users, validate them based on these definitions and making sure who has access or manipulate information of the user.
By defining multiple schemas, you can even differentiate between different personas of your organization or application and restrictions, resp. requirements for them to authenticate.
For example, you could have separate schemas for your employees and your customers. While you might want to make sure that certain data like given name and family name are required for employees, they might be optional for the latter. Or you might want to disable username password authentication for your admins and only allow phishing resistant methods like passkeys, but still allow it for your customers.
Please be aware that User Schema is in a preview stage not feature complete and therefore not generally available.
Do not use it for production yet. To test it out, you need to enable the UserSchema
feature flag.
Create your first schema​
Let's create the first very simple schema user
, which defines a givenName
and familyName
for a user and allows them to
authenticate with username and password.
We can do so by calling the create user schema endpoint with the following data. Make sure to provide an access_token with an IAM_OWNER role.
curl -X POST "https://$CUSTOM-DOMAIN/v3alpha/user_schemas" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
--data-raw '{
"type": "user",
"schema": {
"$schema": "urn:zitadel:schema:v1",
"type": "object",
"properties": {
"givenName": {
"type": "string"
},
"familyName": {
"type": "string"
}
}
},
"possibleAuthenticators": [
"AUTHENTICATOR_TYPE_USERNAME",
"AUTHENTICATOR_TYPE_PASSWORD"
]
}'
This will return something similar to:
{
"id": "257199613398745508",
"details": {
"sequence": "2",
"change_date": "2024-03-07T08:08:35.963956Z",
"resource_owner": "253750309325636004"
}
}
So you successfully create a schema and could use that to manage your users based on that. But let's first checkout some possibilities ZITADEL offers.
Assign Permissions​
In the first step we've created a very simple user
schema with only givenName
and familyName
.
This allows any user with the permission to edit the user's data to change these values.
Let's now update the schema and add some more properties and restrict who's able to retrieve and change data.
By setting urn:zitadel:schema:permission
to fields, we can define the permissions for that field of different user roles / context.
For example by adding it to the givenName
and familyName
we can keep the state from before, where any owner
(e.g. ORG_OWNER)
as well as the user themselves (self
) are allowed to read (r
) and write (w
) the data.
Let's now assume our service provides some profile information of the user on a dedicated page.
Since we do not want the user to be able to change that value, we set the permission of self
to r
, meaning they will be able
to see the profileUri
value, but cannot update it.
Maybe we also have some customerId
, which the user should not even know about. We therefore can simply omit the self
permission
and only set owner
to rw
, so admins are able to read and change the id if needed.
Finally, we call the update user schema endpoint with the following data. Be sure to provide the id of the previously created schema.
curl -X PUT "https://$CUSTOM-DOMAIN/v3alpha/user_schemas/$SCHEMA_ID" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
--data-raw '{
"schema": {
"$schema": "urn:zitadel:schema:v1",
"type": "object",
"properties": {
"givenName": {
"type": "string",
"urn:zitadel:schema:permission": {
"owner": "rw",
"self": "rw"
}
},
"familyName": {
"type": "string",
"urn:zitadel:schema:permission": {
"owner": "rw",
"self": "rw"
}
},
"profileUri": {
"type": "string",
"format": "uri",
"urn:zitadel:schema:permission": {
"owner": "rw",
"self": "r"
}
},
"customerId": {
"type": "string",
"urn:zitadel:schema:permission": {
"owner": "rw"
}
}
}
}
}'
Retrieve the Existing Schemas​
To check the state of existing schemas you can simply list them.
In this case we will query for the one with state active
. Check out the api documentation for detailed information on possible filters.
The API also allows to retrieve a single schema by ID.
curl -X POST "https://$CUSTOM-DOMAIN/v3alpha/user_schemas/search" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
--data-raw '{
"query": {
"offset": "0",
"limit": 100,
"asc": true
},
"sortingColumn": "FIELD_NAME_TYPE",
"queries": [
{
"stateQuery": {
"state": "STATE_ACTIVE"
}
}
]
}'
If you've followed this guide, it should list you a singe schema:
{
"details": {
"totalResult": "1",
"timestamp": "2024-03-21T16:35:19.685700Z"
},
"result": [
{
"id": "259279890237358500",
"details": {
"sequence": "2",
"changeDate": "2024-03-21T16:35:19.685700Z",
"resourceOwner": "224313188550750765"
},
"type": "user",
"state": "STATE_ACTIVE",
"revision": 2,
"schema": {
"$schema": "urn:zitadel:schema:v1",
"properties": {
"customerId": {
"type": "string",
"urn:zitadel:schema:permission": {
"owner": "rw"
}
},
"familyName": {
"type": "string",
"urn:zitadel:schema:permission": {
"owner": "rw",
"self": "rw"
}
},
"givenName": {
"type": "string",
"urn:zitadel:schema:permission": {
"owner": "rw",
"self": "rw"
}
},
"profileUri": {
"format": "uri",
"type": "string",
"urn:zitadel:schema:permission": {
"owner": "rw",
"self": "r"
}
}
},
"type": "object"
},
"possibleAuthenticators": [
"AUTHENTICATOR_TYPE_USERNAME",
"AUTHENTICATOR_TYPE_PASSWORD"
]
}
]
}
Revision​
Note the revision
property, which is currently 2
. Each update to the schema
-property will increase
it by 1
. The revision will later be reflected on the managed users to state based on which revision of the schema
they were last updated on.