This guide covers common user management operations including creating users, updating profiles, managing authentication factors, and handling user lifecycle.
Prerequisites
Before you begin, ensure you have:
- Installed the Zitadel Ruby SDK
- Configured authentication (PAT, Client Credentials, or Private Key JWT)
- Appropriate permissions (
user.read, user.write)
Creating Users
Creating a Human User
Human users represent actual people who can log in to your application.
require 'zitadel-client'
require 'securerandom'
# Initialize the client
client = Zitadel::Client::Zitadel.with_access_token(
"https://example.zitadel.cloud",
"your_access_token"
)
# Create a human user
request = Zitadel::Client::UserServiceCreateUserRequest.new(
organization: {
org_id: "your_org_id"
},
user: {
human: {
username: "[email protected]",
profile: {
given_name: "John",
family_name: "Doe",
display_name: "John Doe"
},
email: {
email: "[email protected]",
is_verified: false
},
password: {
password: "SecurePassword123!",
change_required: true
}
}
}
)
begin
response = client.users.create_user(request)
puts "User created with ID: #{response.user_id}"
rescue Zitadel::Client::ApiError => e
puts "Error creating user: #{e.message}"
end
The create_user method is the preferred way to create users. The older add_human_user method is deprecated but still available for backward compatibility.
Creating a Machine User
Machine users are service accounts used for API access and automation.
request = Zitadel::Client::UserServiceCreateUserRequest.new(
organization: {
org_id: "your_org_id"
},
user: {
machine: {
username: "api-service",
name: "API Service Account",
description: "Service account for API integration",
access_token_type: "ACCESS_TOKEN_TYPE_BEARER"
}
}
)
response = client.users.create_user(request)
puts "Machine user created with ID: #{response.user_id}"
Get User by ID
request = Zitadel::Client::UserServiceGetUserByIDRequest.new(
user_id: "user_id_here"
)
response = client.users.get_user_by_id(request)
if response.user.human
puts "User: #{response.user.human.profile.display_name}"
puts "Email: #{response.user.human.email.email}"
elsif response.user.machine
puts "Machine: #{response.user.machine.name}"
end
Updating User Profiles
Update Human User Profile
request = Zitadel::Client::UserServiceUpdateHumanUserRequest.new(
user_id: "user_id_here",
profile: {
given_name: "Jane",
family_name: "Smith",
display_name: "Jane Smith",
preferred_language: "en"
}
)
response = client.users.update_human_user(request)
puts "User profile updated"
Update Email Address
request = Zitadel::Client::UserServiceSetEmailRequest.new(
user_id: "user_id_here",
email: "[email protected]",
is_verified: false,
send_code: {
url_template: "https://example.com/verify?code={{.Code}}"
}
)
response = client.users.set_email(request)
puts "Email updated and verification code sent"
Managing Authentication
Add Personal Access Token (Machine Users)
Personal Access Tokens allow machine users to authenticate to the API.
request = Zitadel::Client::UserServiceAddPersonalAccessTokenRequest.new(
user_id: "machine_user_id",
expiration_date: (Time.now + 365 * 24 * 60 * 60).to_s # 1 year
)
response = client.users.add_personal_access_token(request)
puts "Token: #{response.token}"
puts "Token ID: #{response.token_id}"
Store the returned token securely. It cannot be retrieved again after creation.
Add API Key (Machine Users)
API keys are used for JWT profile authentication.
request = Zitadel::Client::UserServiceAddKeyRequest.new(
user_id: "machine_user_id",
type: "KEY_TYPE_JSON",
expiration_date: (Time.now + 365 * 24 * 60 * 60).to_s
)
response = client.users.add_key(request)
puts "Key ID: #{response.key_id}"
puts "Key Details: #{response.key_details}"
Add Multi-Factor Authentication
Add OTP Email
request = Zitadel::Client::UserServiceAddOTPEmailRequest.new(
user_id: "user_id_here"
)
response = client.users.add_otp_email(request)
puts "OTP Email added successfully"
Add OTP SMS
request = Zitadel::Client::UserServiceAddOTPSMSRequest.new(
user_id: "user_id_here"
)
response = client.users.add_otp_sms(request)
puts "OTP SMS added successfully"
User Lifecycle Management
Deactivate User
Deactivating a user prevents them from logging in while preserving their data.
request = Zitadel::Client::UserServiceDeactivateUserRequest.new(
user_id: "user_id_here"
)
response = client.users.deactivate_user(request)
puts "User deactivated"
Use deactivation when you need to temporarily disable an account but may reactivate it later.
Reactivate User
request = Zitadel::Client::UserServiceReactivateUserRequest.new(
user_id: "user_id_here"
)
response = client.users.reactivate_user(request)
puts "User reactivated"
Delete User
Deleting a user permanently removes their ability to log in and marks them as deleted.
request = Zitadel::Client::UserServiceDeleteUserRequest.new(
user_id: "user_id_here"
)
response = client.users.delete_user(request)
puts "User deleted"
User deletion is permanent. The user will not be able to log in, and API calls referencing this user will return “User not found” errors.
require 'base64'
request = Zitadel::Client::UserServiceSetUserMetadataRequest.new(
user_id: "user_id_here",
key: "preferences",
value: Base64.strict_encode64('{"theme": "dark", "language": "en"}')
)
response = client.users.set_user_metadata(request)
puts "Metadata updated"
request = Zitadel::Client::UserServiceDeleteUserMetadataRequest.new(
user_id: "user_id_here",
key: "preferences"
)
response = client.users.delete_user_metadata(request)
puts "Metadata deleted"
Creating Invite Codes
Invite codes allow users to set up their initial authentication method.
request = Zitadel::Client::UserServiceCreateInviteCodeRequest.new(
user_id: "user_id_here",
application_name: "My Application",
url_template: "https://myapp.com/register?code={{.Code}}&userID={{.UserID}}"
)
response = client.users.create_invite_code(request)
puts "Invite code: #{response.code}"
Listing and Searching Users
List All Users
request = Zitadel::Client::UserServiceListUsersRequest.new(
queries: [],
sorting_column: "FIELD_NAME_CREATION_DATE",
asc: false
)
response = client.users.list_users(request)
response.result.each do |user|
if user.human
puts "User: #{user.human.profile.display_name}"
elsif user.machine
puts "Machine: #{user.machine.name}"
end
end
Error Handling
begin
response = client.users.create_user(request)
puts "Success: #{response.user_id}"
rescue Zitadel::Client::ApiError => e
case e.code
when 409
puts "User already exists"
when 400
puts "Invalid request: #{e.message}"
when 403
puts "Permission denied"
else
puts "Error: #{e.message}"
end
end
Best Practices
Secure credential storage
Never log or store Personal Access Tokens or API keys in plain text. Use secure credential management systems.
Use appropriate user types
Create human users for people and machine users for services. Don’t use human users for API access.
Implement proper error handling
Always wrap API calls in error handling to gracefully manage failures.
For human users, send verification codes to ensure email ownership.
Store application-specific user data in metadata rather than creating custom user fields.
Next Steps