Skip to main content
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}"

Retrieving User Information

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.

Managing User Metadata

Set User Metadata

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"

Delete User Metadata

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

1
Secure credential storage
2
Never log or store Personal Access Tokens or API keys in plain text. Use secure credential management systems.
3
Use appropriate user types
4
Create human users for people and machine users for services. Don’t use human users for API access.
5
Implement proper error handling
6
Always wrap API calls in error handling to gracefully manage failures.
7
Verify email addresses
8
For human users, send verification codes to ensure email ownership.
9
Use metadata for custom data
10
Store application-specific user data in metadata rather than creating custom user fields.

Next Steps

Build docs developers (and LLMs) love