Skip to main content

What are Service Users?

Service users in Zitadel are specialized accounts designed for machine-to-machine (M2M) communication and server-to-server authentication. Unlike regular human users who authenticate through interactive login flows, service users are intended for automated processes, backend services, and API integrations.
The Zitadel Ruby SDK is specifically designed for service user authentication and does not support interactive user authentication flows like OAuth2, OIDC, or SAML for client applications.

Service Users vs. Human Users

FeatureService UsersHuman Users
PurposeAutomated API access, M2M communicationInteractive application access
AuthenticationPrivate key JWT, Client Credentials, PATOAuth2, OIDC, SAML, password
Login FlowProgrammatic, non-interactiveInteractive browser-based
Use CaseBackend services, cron jobs, integrationsWeb apps, mobile apps, user portals
Supported by SDK✅ Full support❌ Not supported

Use Cases for Service Users

Service users are ideal for:
  • Backend Services: Authenticate your Ruby application to access Zitadel APIs
  • Scheduled Tasks: Automate user provisioning, synchronization, or cleanup jobs
  • Microservices: Enable service-to-service communication within your architecture
  • CI/CD Pipelines: Automate deployments and infrastructure management
  • Data Integration: Sync user data between Zitadel and external systems

Authentication Methods

The SDK provides three authentication methods for service users: Most secure option using asymmetric cryptography. The service user signs JWTs with a private key stored in a JSON file.
require 'zitadel-client'

# Initialize with private key JWT
client = Zitadel::Client::Zitadel.with_private_key(
  "https://example.us1.zitadel.cloud",
  "path/to/jwt-key.json"
)

# Use the client
response = client.users.list_users(
  Zitadel::Client::UserServiceListUsersRequest.new(limit: 10)
)
Private Key JWT offers the strongest security as the secret never leaves your infrastructure. Learn more in the Zitadel documentation.

2. Client Credentials Grant

OAuth2-based authentication using a client ID and secret. The SDK automatically handles token acquisition and refresh.
require 'zitadel-client'

# Initialize with client credentials
client = Zitadel::Client::Zitadel.with_client_credentials(
  "https://example.us1.zitadel.cloud",
  "your-client-id",
  "your-client-secret"
)

# Token management is handled automatically
response = client.organizations.list_organizations(
  Zitadel::Client::OrganizationServiceListOrganizationsRequest.new
)
Store your client secret securely. Never commit it to version control or expose it in client-side code.

3. Personal Access Token (PAT)

Simplest method using a pre-generated token. Best for development and testing.
require 'zitadel-client'

# Initialize with PAT
client = Zitadel::Client::Zitadel.with_access_token(
  "https://example.us1.zitadel.cloud",
  "your-personal-access-token"
)

# Quick setup for testing
response = client.users.get_user_by_id(
  Zitadel::Client::UserServiceGetUserByIdRequest.new(user_id: "123456789")
)
PATs are convenient for development but should be rotated regularly in production. They don’t support automatic token refresh.

Creating a Service User

To create a service user in Zitadel:
  1. Navigate to your Zitadel Console
  2. Go to Users > Service Users
  3. Click “New Service User”
  4. Configure authentication method (JWT, Client Credentials, or PAT)
  5. Assign necessary roles and permissions
  6. Download credentials (private key JSON or note client secret/PAT)
# After creating the service user in Zitadel Console,
# initialize your SDK with the downloaded credentials

client = Zitadel::Client::Zitadel.with_private_key(
  "https://example.us1.zitadel.cloud",
  "service-account-key.json"
)

# Now you can manage users programmatically
new_user = client.users.add_human_user(
  Zitadel::Client::UserServiceAddHumanUserRequest.new(
    username: "john.doe",
    profile: Zitadel::Client::UserServiceSetHumanProfile.new(
      given_name: "John",
      family_name: "Doe"
    ),
    email: Zitadel::Client::UserServiceSetHumanEmail.new(
      email: "[email protected]"
    )
  )
)

puts "Created user: #{new_user.user_id}"

Security Best Practices

  1. Use Private Key JWT in production for maximum security
  2. Rotate credentials regularly, especially PATs
  3. Apply principle of least privilege - grant only necessary permissions
  4. Store credentials securely using environment variables or secret management services
  5. Monitor service user activity through Zitadel audit logs
  6. Never share credentials between different services or environments

Common Patterns

Environment-Based Configuration

require 'zitadel-client'

# Load credentials from environment variables
client = case ENV['ZITADEL_AUTH_METHOD']
         when 'private_key'
           Zitadel::Client::Zitadel.with_private_key(
             ENV['ZITADEL_HOST'],
             ENV['ZITADEL_KEY_FILE']
           )
         when 'client_credentials'
           Zitadel::Client::Zitadel.with_client_credentials(
             ENV['ZITADEL_HOST'],
             ENV['ZITADEL_CLIENT_ID'],
             ENV['ZITADEL_CLIENT_SECRET']
           )
         else
           Zitadel::Client::Zitadel.with_access_token(
             ENV['ZITADEL_HOST'],
             ENV['ZITADEL_ACCESS_TOKEN']
           )
         end

Rails Initializer

# config/initializers/zitadel.rb
require 'zitadel-client'

ZITADEL_CLIENT = Zitadel::Client::Zitadel.with_private_key(
  Rails.application.credentials.dig(:zitadel, :host),
  Rails.root.join('config', 'zitadel-service-account.json').to_s
)

# Use in your application
# ZITADEL_CLIENT.users.list_users(...)

Next Steps

Build docs developers (and LLMs) love