Class: Kward::RPC::AuthManager

Inherits:
Object
  • Object
show all
Defined in:
lib/kward/rpc/auth_manager.rb

Overview

RPC authentication manager for provider status, login, and logout requests.

Defined Under Namespace

Classes: Login

Instance Method Summary collapse

Constructor Details

#initialize(server:, oauth_factory: -> { OpenAIOAuth.new }, github_oauth_factory: -> { GithubOAuth.new }, anthropic_oauth_factory: -> { AnthropicOAuth.new }, config_manager: ConfigManager.new) ⇒ AuthManager

Returns a new instance of AuthManager.



17
18
19
20
21
22
23
24
25
# File 'lib/kward/rpc/auth_manager.rb', line 17

def initialize(server:, oauth_factory: -> { OpenAIOAuth.new }, github_oauth_factory: -> { GithubOAuth.new }, anthropic_oauth_factory: -> { AnthropicOAuth.new }, config_manager: ConfigManager.new)
  @server = server
  @oauth_factory = oauth_factory
  @github_oauth_factory = github_oauth_factory
  @anthropic_oauth_factory = anthropic_oauth_factory
  @config_manager = config_manager
  @logins = {}
  @mutex = Mutex.new
end

Instance Method Details

#login_status(login_id:) ⇒ Object



118
119
120
# File 'lib/kward/rpc/auth_manager.rb', line 118

def (login_id:)
  (())
end

#login_with_api_key(provider_id:, api_key:) ⇒ Object



46
47
48
49
50
# File 'lib/kward/rpc/auth_manager.rb', line 46

def (provider_id:, api_key:)
  provider_id = provider_id.to_s
  @config_manager.set_api_key(provider_id, api_key)
  { providerId: provider_id, message: "Saved API key for #{provider_name(provider_id)}." }
end

#login_with_oauth(provider_id:, timeout_seconds: 120) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/kward/rpc/auth_manager.rb', line 69

def (provider_id:, timeout_seconds: 120)
  provider_id = provider_id.to_s
  case provider_id
  when "openai"
    (provider_id: "openai", oauth: @oauth_factory.call, timeout_seconds: timeout_seconds)
  when "anthropic"
    (provider_id: "anthropic", oauth: @anthropic_oauth_factory.call, timeout_seconds: timeout_seconds)
  when "github"
    raise "GitHub OAuth is supported in the CLI with `ruby lib/main.rb login github`, but RPC browser login is not implemented yet."
  else
    raise "Unsupported OAuth provider: #{provider_id}"
  end
end

#logout_provider(provider_id:) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/kward/rpc/auth_manager.rb', line 52

def logout_provider(provider_id:)
  provider_id = provider_id.to_s
  case provider_id
  when "openai"
    logout_openai
    { providerId: provider_id, message: "Logged out of OpenAI." }
  when "anthropic"
    logout_anthropic
    { providerId: provider_id, message: "Logged out of Anthropic." }
  when "openrouter"
    @config_manager.delete_key("openrouter_api_key")
    { providerId: provider_id, message: "Logged out of OpenRouter." }
  else
    raise "Unsupported auth provider: #{provider_id}"
  end
end

#providersObject



42
43
44
# File 'lib/kward/rpc/auth_manager.rb', line 42

def providers
  { providers: [openai_provider, anthropic_provider, openrouter_provider, github_provider] }
end

#start_oauth_login(provider_id:, oauth:, timeout_seconds: 120) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/kward/rpc/auth_manager.rb', line 87

def (provider_id:, oauth:, timeout_seconds: 120)
  flow = oauth.
  pkce = flow.fetch(:pkce)
  state = flow.fetch(:state)
  server = flow.fetch(:server)
  redirect_uri = flow.fetch(:redirect_uri)
  url = flow.fetch(:authorization_url)
   = Login.new(
    id: SecureRandom.uuid,
    provider_id: provider_id,
    oauth: oauth,
    pkce: pkce,
    state: state,
    server: server,
    redirect_uri: redirect_uri,
    status: "pending"
  )
  @mutex.synchronize { @logins[.id] =  }
  .thread = Thread.new { wait_for_callback(, timeout_seconds: timeout_seconds.to_i <= 0 ? 120 : timeout_seconds.to_i) }
  { providerId: provider_id, loginId: .id, authorizationUrl: url, redirectUri: redirect_uri, status: .status }
end

#start_openai_login(timeout_seconds: 120) ⇒ Object



83
84
85
# File 'lib/kward/rpc/auth_manager.rb', line 83

def (timeout_seconds: 120)
  (provider_id: "openai", oauth: @oauth_factory.call, timeout_seconds: timeout_seconds)
end

#statusObject



27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/kward/rpc/auth_manager.rb', line 27

def status
  oauth = @oauth_factory.call
  config = stored_config
  {
    openaiOAuth: oauth.logged_in?,
    openaiAccountId: oauth.respond_to?(:account_id) ? oauth. : nil,
    openrouterApiKey: !ENV["OPENROUTER_API_KEY"].to_s.empty? || !config["openrouter_api_key"].to_s.empty?,
    openaiAccessToken: !ENV["OPENAI_ACCESS_TOKEN"].to_s.empty?,
    anthropicOAuth: @anthropic_oauth_factory.call.logged_in?,
    githubOAuth: @github_oauth_factory.call.logged_in?
  }
rescue StandardError => e
  { openaiOAuth: false, error: e.message }
end

#submit_openai_code(login_id:, code:) ⇒ Object



109
110
111
112
113
114
115
116
# File 'lib/kward/rpc/auth_manager.rb', line 109

def submit_openai_code(login_id:, code:)
   = ()
  raise "Login is not pending" unless .status == "pending"

  code = .oauth.authorization_code_from(code.to_s, expected_state: .state)
  (, code)
  ()
end