Skip to main content
Deprecated: Please move to the corresponding endpoints under OIDC Service v2. This service will be removed in the next major version of ZITADEL.

Overview

The BetaOIDCServiceApi provides methods for managing OpenID Connect authentication flows and authorization requests.

Initialization

require 'zitadel/client'

client = Zitadel::Client::ApiClient.new
client.config.access_token = 'your_access_token'

oidc_service = Zitadel::Client::Api::BetaOIDCServiceApi.new(client)

Key Methods

Authorization Requests

beta_oidc_service_get_auth_request_request
object
required
Request with auth request ID
# Get auth request ID from redirect URL parameter
auth_request_id = params[:authRequestId]

request = Zitadel::Client::Models::BetaOIDCServiceGetAuthRequestRequest.new(
  auth_request_id: auth_request_id
)

response = oidc_service.get_auth_request(request)

puts "Client ID: #{response.client_id}"
puts "Redirect URI: #{response.redirect_uri}"
puts "Scope: #{response.scope}"
puts "Prompt: #{response.prompt}"
Returns: BetaOIDCServiceGetAuthRequestResponse containing:
  • Application details
  • Requested scopes
  • Response type
  • Redirect URI
  • PKCE challenge (if used)
  • Login hint
  • UI locales

Callback Creation

beta_oidc_service_create_callback_request
object
required
Request to finalize auth request
# After successful authentication
request = Zitadel::Client::Models::BetaOIDCServiceCreateCallbackRequest.new(
  auth_request_id: auth_request_id,
  session_id: session_id # From successful login
)

response = oidc_service.create_callback(request)

# Redirect user to callback URL
if response.callback_url
  redirect_to response.callback_url
else
  # Handle error
  puts "Error: #{response.details.reason_phrase}"
end
Returns: BetaOIDCServiceCreateCallbackResponse containing:
  • callback_url - URL to redirect user (includes auth code or error)
  • details - Request metadata
This method can only be called once per auth request. The callback URL contains either:
  • Success: authorization code or tokens (implicit flow)
  • Failure: error code and description

OAuth 2.0 / OIDC Flow

Authorization Code Flow

  1. User initiates login
    • Application redirects to ZITADEL authorize endpoint
    • User is redirected back with authRequestId
  2. Get auth request details
    request = Zitadel::Client::Models::BetaOIDCServiceGetAuthRequestRequest.new(
      auth_request_id: params[:authRequestId]
    )
    
    auth_request = oidc_service.get_auth_request(request)
    
  3. Authenticate user
    • Verify credentials
    • Create or get session
    • Optionally perform MFA
  4. Create callback
    request = Zitadel::Client::Models::BetaOIDCServiceCreateCallbackRequest.new(
      auth_request_id: params[:authRequestId],
      session_id: user_session.id
    )
    
    callback = oidc_service.create_callback(request)
    redirect_to callback.callback_url
    
  5. Exchange code for tokens
    • Application backend calls token endpoint
    • Receives access token, ID token, refresh token

PKCE (Proof Key for Code Exchange)

For enhanced security in public clients:
# Auth request will contain PKCE challenge
auth_request = oidc_service.get_auth_request(request)

if auth_request.code_challenge
  puts "PKCE Challenge: #{auth_request.code_challenge}"
  puts "Challenge Method: #{auth_request.code_challenge_method}"
  # Validate challenge when creating callback
end

Response Types

The auth request specifies the response type:
  • CODE - Authorization code flow (most secure)
  • ID_TOKEN - Implicit flow (ID token only)
  • ID_TOKEN TOKEN - Implicit flow (ID + access token)
auth_request = oidc_service.get_auth_request(request)

case auth_request.response_type
when 'CODE'
  # Handle authorization code flow
when 'ID_TOKEN'
  # Handle implicit flow
end

Scopes

Requested scopes are included in the auth request:
auth_request = oidc_service.get_auth_request(request)

auth_request.scope.each do |scope|
  puts "Requested scope: #{scope}"
end

# Common scopes:
# - openid (required for OIDC)
# - profile (user profile info)
# - email (user email)
# - offline_access (refresh token)
# - urn:zitadel:iam:org:project:id:{project_id}:aud (project roles)

Prompt Parameter

Controls authentication behavior:
auth_request = oidc_service.get_auth_request(request)

case auth_request.prompt
when 'NONE'
  # Silent auth - fail if user not authenticated
when 'LOGIN'
  # Force re-authentication
when 'CONSENT'
  # Show consent screen
when 'SELECT_ACCOUNT'
  # Show account selector
end

Login Hint

Pre-fill login form:
auth_request = oidc_service.get_auth_request(request)

if auth_request.login_hint
  # Pre-fill username field
  @username = auth_request.login_hint
end

UI Locales

Preferred languages for UI:
auth_request = oidc_service.get_auth_request(request)

if auth_request.ui_locales
  # Set UI language
  I18n.locale = auth_request.ui_locales.first
end

Error Handling

Invalid Auth Request

begin
  response = oidc_service.get_auth_request(request)
rescue Zitadel::Client::ApiError => e
  if e.code == 404
    # Auth request not found or expired
    redirect_to login_path, alert: 'Invalid or expired request'
  else
    # Other error
    raise e
  end
end

Callback Errors

response = oidc_service.create_callback(request)

# Check if callback URL contains error
if response.callback_url.include?('error=')
  # OAuth error in callback
  # User will see error at application
  redirect_to response.callback_url
else
  # Success - contains authorization code
  redirect_to response.callback_url
end

Complete Example

class OAuthController < ApplicationController
  def authorize
    # Get auth request details
    request = Zitadel::Client::Models::BetaOIDCServiceGetAuthRequestRequest.new(
      auth_request_id: params[:authRequestId]
    )
    
    @auth_request = oidc_service.get_auth_request(request)
    
    # Show login form
    render :login
  end
  
  def authenticate
    # Authenticate user
    user = authenticate_user(params[:username], params[:password])
    
    if user
      # Create or get session
      session = create_user_session(user)
      
      # Create callback
      request = Zitadel::Client::Models::BetaOIDCServiceCreateCallbackRequest.new(
        auth_request_id: params[:authRequestId],
        session_id: session.id
      )
      
      response = oidc_service.create_callback(request)
      redirect_to response.callback_url
    else
      redirect_to authorize_path(authRequestId: params[:authRequestId]),
                  alert: 'Invalid credentials'
    end
  end
  
  private
  
  def oidc_service
    @oidc_service ||= begin
      client = Zitadel::Client::ApiClient.new
      client.config.access_token = service_account_token
      Zitadel::Client::Api::BetaOIDCServiceApi.new(client)
    end
  end
end

Security Considerations

  • Always validate auth request before showing login form
  • Verify PKCE challenge if present
  • Use state parameter to prevent CSRF
  • Only call create_callback once per auth request
  • Use HTTPS for all redirects
  • Validate redirect_uri matches registered URIs

Migration Guide

To migrate to OIDC Service v2:
  1. Replace BetaOIDCServiceApi with OIDCServiceV2Api
  2. Update request/response models
  3. Review callback URL structure
  4. Test complete OAuth flows

See Also

Build docs developers (and LLMs) love