Module: AgentHarness::Authentication
- Defined in:
- lib/agent_harness/authentication.rb
Overview
Authentication management for CLI agent providers
Provides methods for checking auth status, generating OAuth URLs, and refreshing credentials for providers that support it.
Class Method Summary collapse
-
.auth_capabilities(provider_name) ⇒ Hash
Get authentication flow capabilities for a provider.
-
.auth_status(provider_name) ⇒ Hash
Get detailed authentication status for a provider.
-
.auth_url(provider_name) ⇒ String
Generate an OAuth URL for a provider.
-
.auth_url_supported?(provider_name) ⇒ Boolean
Check whether OAuth URL generation is supported for a provider.
-
.auth_valid?(provider_name) ⇒ Boolean
Check if authentication is valid for a provider.
-
.exchange_code(provider_name, code:, code_verifier:, redirect_uri:, client_id:, state: nil) ⇒ Hash
Exchange a PKCE authorization code for tokens and persist them in native shape.
-
.exchange_code_supported?(provider_name) ⇒ Boolean
Check whether PKCE authorization-code exchange is supported for a provider.
-
.exchange_refresh_token(provider_name) ⇒ Hash
Exchange a stored refresh token for a fresh access token (and rotated refresh token).
-
.exchange_refresh_token_supported?(provider_name) ⇒ Boolean
Check whether refresh-token exchange is supported for a provider.
-
.refresh_auth(provider_name, token: nil) ⇒ Hash
Refresh authentication credentials for a provider.
-
.refresh_auth_supported?(provider_name) ⇒ Boolean
Check whether credential refresh is supported for a provider.
Class Method Details
.auth_capabilities(provider_name) ⇒ Hash
Get authentication flow capabilities for a provider.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/agent_harness/authentication.rb', line 45 def auth_capabilities(provider_name) provider_name = provider_name.to_sym provider = resolve_provider(provider_name) canonical_name = Providers::Registry.instance.canonical_name(provider_name) flow_supported = claude_oauth_flow_provider?(provider_name, canonical_name) { auth_type: provider.auth_type, auth_url: flow_supported, refresh: flow_supported, exchange: flow_supported, code_exchange: flow_supported } end |
.auth_status(provider_name) ⇒ Hash
Get detailed authentication status for a provider
30 31 32 33 34 35 36 37 38 |
# File 'lib/agent_harness/authentication.rb', line 30 def auth_status(provider_name) provider_name = provider_name.to_sym case provider_name when :claude, :anthropic claude_auth_status else generic_auth_status(provider_name) end end |
.auth_url(provider_name) ⇒ String
Generate an OAuth URL for a provider
Only supported for :oauth auth type providers.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/agent_harness/authentication.rb', line 76 def auth_url(provider_name) provider_name = provider_name.to_sym provider = resolve_provider(provider_name) unless provider.auth_type == :oauth raise UnsupportedAuthFlowError, "Provider #{provider_name} uses #{provider.auth_type} auth and does not support OAuth URL generation" end case provider_name when :claude, :anthropic claude_auth_url else raise UnsupportedAuthFlowError, "OAuth URL generation is not yet implemented for provider #{provider_name}" end end |
.auth_url_supported?(provider_name) ⇒ Boolean
Check whether OAuth URL generation is supported for a provider.
65 66 67 |
# File 'lib/agent_harness/authentication.rb', line 65 def auth_url_supported?(provider_name) auth_capabilities(provider_name)[:auth_url] end |
.auth_valid?(provider_name) ⇒ Boolean
Check if authentication is valid for a provider
21 22 23 24 |
# File 'lib/agent_harness/authentication.rb', line 21 def auth_valid?(provider_name) status = auth_status(provider_name) !!status[:valid] end |
.exchange_code(provider_name, code:, code_verifier:, redirect_uri:, client_id:, state: nil) ⇒ Hash
Exchange a PKCE authorization code for tokens and persist them in native shape.
Posts the authorization code and PKCE verifier to the provider’s OAuth token endpoint, then writes the resulting access/refresh tokens to the credentials store using the provider’s native shape (e.g. claudeAiOauth for Claude).
Serializes through a file lock so that concurrent callers do not race on credential writes.
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/agent_harness/authentication.rb', line 206 def exchange_code(provider_name, code:, code_verifier:, redirect_uri:, client_id:, state: nil) provider_name = provider_name.to_sym provider = resolve_provider(provider_name) unless provider.auth_type == :oauth raise UnsupportedAuthFlowError, "Provider #{provider_name} uses #{provider.auth_type} auth and does not support code exchange" end validate_code_exchange_params!(code: code, code_verifier: code_verifier, redirect_uri: redirect_uri, client_id: client_id) case provider_name when :claude, :anthropic exchange_claude_code( code: code.strip, code_verifier: code_verifier.strip, redirect_uri: redirect_uri.strip, client_id: client_id.strip, state: state ) else raise UnsupportedAuthFlowError, "Code exchange is not yet implemented for provider #{provider_name}" end end |
.exchange_code_supported?(provider_name) ⇒ Boolean
Check whether PKCE authorization-code exchange is supported for a provider.
181 182 183 |
# File 'lib/agent_harness/authentication.rb', line 181 def exchange_code_supported?(provider_name) auth_capabilities(provider_name)[:code_exchange] end |
.exchange_refresh_token(provider_name) ⇒ Hash
Exchange a stored refresh token for a fresh access token (and rotated refresh token).
Reads the refresh token from the provider’s credentials store, posts it to the OAuth token endpoint, persists the rotated tokens, and returns the credential in native claudeAiOauth shape.
Serializes through a file lock so that concurrent callers do not race on a single-use/rotating refresh token. If the token server reports that the refresh token has already been consumed (‘refresh_token_reused`), raises AuthenticationError so the caller can trigger a full re-auth.
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/agent_harness/authentication.rb', line 158 def exchange_refresh_token(provider_name) provider_name = provider_name.to_sym provider = resolve_provider(provider_name) unless provider.auth_type == :oauth raise UnsupportedAuthFlowError, "Provider #{provider_name} uses #{provider.auth_type} auth and does not support token exchange" end case provider_name when :claude, :anthropic exchange_claude_refresh_token else raise UnsupportedAuthFlowError, "Token exchange is not yet implemented for provider #{provider_name}" end end |
.exchange_refresh_token_supported?(provider_name) ⇒ Boolean
Check whether refresh-token exchange is supported for a provider.
138 139 140 |
# File 'lib/agent_harness/authentication.rb', line 138 def exchange_refresh_token_supported?(provider_name) auth_capabilities(provider_name)[:exchange] end |
.refresh_auth(provider_name, token: nil) ⇒ Hash
Refresh authentication credentials for a provider
For OAuth providers, stores a pre-exchanged token directly. This method accepts a token (not an authorization code) because the OAuth code-exchange flow is provider-specific and should be handled by the caller or a CLI login command before calling this. For API key providers, raises UnsupportedAuthFlowError.
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/agent_harness/authentication.rb', line 115 def refresh_auth(provider_name, token: nil) provider_name = provider_name.to_sym provider = resolve_provider(provider_name) unless provider.auth_type == :oauth raise UnsupportedAuthFlowError, "Provider #{provider_name} uses #{provider.auth_type} auth and does not support credential refresh" end case provider_name when :claude, :anthropic refresh_claude_auth(token: token) else raise UnsupportedAuthFlowError, "Credential refresh is not yet implemented for provider #{provider_name}" end end |
.refresh_auth_supported?(provider_name) ⇒ Boolean
Check whether credential refresh is supported for a provider.
99 100 101 |
# File 'lib/agent_harness/authentication.rb', line 99 def refresh_auth_supported?(provider_name) auth_capabilities(provider_name)[:refresh] end |