feat: OpenAICompatibleOAuthProvider (config-driven OAuthProvider impl)
This commit is contained in:
@@ -25,8 +25,8 @@ impl OAuthProvider for ClaudeOAuthProvider {
|
||||
"https://console.anthropic.com/oauth/code/callback"
|
||||
}
|
||||
|
||||
fn scopes(&self) -> &str {
|
||||
"org:create_api_key user:profile user:inference"
|
||||
fn scopes(&self) -> String {
|
||||
"org:create_api_key user:profile user:inference".to_string()
|
||||
}
|
||||
|
||||
fn extra_authorize_params(&self) -> Vec<(&str, &str)> {
|
||||
|
||||
@@ -27,8 +27,8 @@ impl OAuthProvider for GeminiOAuthProvider {
|
||||
""
|
||||
}
|
||||
|
||||
fn scopes(&self) -> &str {
|
||||
"https://www.googleapis.com/auth/generative-language.peruserquota https://www.googleapis.com/auth/generative-language.retriever https://www.googleapis.com/auth/userinfo.email"
|
||||
fn scopes(&self) -> String {
|
||||
"https://www.googleapis.com/auth/generative-language.peruserquota https://www.googleapis.com/auth/generative-language.retriever https://www.googleapis.com/auth/userinfo.email".to_string()
|
||||
}
|
||||
|
||||
fn client_secret(&self) -> Option<&str> {
|
||||
|
||||
@@ -4,6 +4,7 @@ mod common;
|
||||
mod gemini_oauth;
|
||||
mod message;
|
||||
pub mod oauth;
|
||||
mod openai_compatible_oauth;
|
||||
mod openai_oauth;
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
+4
-3
@@ -118,7 +118,7 @@ pub trait OAuthProvider: Send + Sync {
|
||||
fn authorize_url(&self) -> &str;
|
||||
fn token_url(&self) -> &str;
|
||||
fn redirect_uri(&self) -> &str;
|
||||
fn scopes(&self) -> &str;
|
||||
fn scopes(&self) -> String;
|
||||
|
||||
fn client_secret(&self) -> Option<&str> {
|
||||
None
|
||||
@@ -204,7 +204,8 @@ async fn run_pkce_flow(provider: &dyn OAuthProvider, client_name: &str) -> Resul
|
||||
(provider.redirect_uri().to_string(), false)
|
||||
};
|
||||
|
||||
let encoded_scopes = urlencoding::encode(provider.scopes());
|
||||
let scopes = provider.scopes();
|
||||
let encoded_scopes = urlencoding::encode(&scopes);
|
||||
let encoded_redirect = urlencoding::encode(&redirect_uri);
|
||||
|
||||
let mut authorize_url = format!(
|
||||
@@ -313,7 +314,7 @@ async fn run_client_credentials_flow(
|
||||
("client_id", provider.client_id()),
|
||||
];
|
||||
if !scopes.is_empty() {
|
||||
params.push(("scope", scopes));
|
||||
params.push(("scope", scopes.as_str()));
|
||||
}
|
||||
|
||||
let request = build_token_request(&client, provider, ¶ms);
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
use super::oauth::{OAuthConfig, OAuthFlow, OAuthProvider, TokenRequestFormat};
|
||||
|
||||
pub struct OpenAICompatibleOAuthProvider {
|
||||
pub config: OAuthConfig,
|
||||
pub client_name: String,
|
||||
}
|
||||
|
||||
impl OAuthProvider for OpenAICompatibleOAuthProvider {
|
||||
fn provider_name(&self) -> &str {
|
||||
&self.client_name
|
||||
}
|
||||
|
||||
fn client_id(&self) -> &str {
|
||||
&self.config.client_id
|
||||
}
|
||||
|
||||
fn authorize_url(&self) -> &str {
|
||||
self.config.authorize_url.as_deref().unwrap_or("")
|
||||
}
|
||||
|
||||
fn token_url(&self) -> &str {
|
||||
&self.config.token_url
|
||||
}
|
||||
|
||||
fn redirect_uri(&self) -> &str {
|
||||
self.config.redirect_uri.as_deref().unwrap_or("")
|
||||
}
|
||||
|
||||
fn scopes(&self) -> String {
|
||||
self.config.scopes.join(" ")
|
||||
}
|
||||
|
||||
fn client_secret(&self) -> Option<&str> {
|
||||
self.config.client_secret.as_deref()
|
||||
}
|
||||
|
||||
fn extra_authorize_params(&self) -> Vec<(&str, &str)> {
|
||||
self.config
|
||||
.extra_authorize_params
|
||||
.iter()
|
||||
.map(|(k, v)| (k.as_str(), v.as_str()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn token_request_format(&self) -> TokenRequestFormat {
|
||||
self.config
|
||||
.token_request_format
|
||||
.unwrap_or(TokenRequestFormat::FormUrlEncoded)
|
||||
}
|
||||
|
||||
fn uses_localhost_redirect(&self) -> bool {
|
||||
self.config.redirect_uri.is_none() && self.config.redirect_port.is_none()
|
||||
}
|
||||
|
||||
fn fixed_redirect_uri(&self) -> Option<String> {
|
||||
if let Some(uri) = &self.config.redirect_uri {
|
||||
return Some(uri.clone());
|
||||
}
|
||||
if let Some(port) = self.config.redirect_port {
|
||||
return Some(format!("http://127.0.0.1:{port}/callback"));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn extra_token_headers(&self) -> Vec<(&str, &str)> {
|
||||
self.config
|
||||
.extra_token_headers
|
||||
.iter()
|
||||
.map(|(k, v)| (k.as_str(), v.as_str()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn extra_request_headers(&self) -> Vec<(&str, &str)> {
|
||||
self.config
|
||||
.extra_request_headers
|
||||
.iter()
|
||||
.map(|(k, v)| (k.as_str(), v.as_str()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn flow(&self) -> OAuthFlow {
|
||||
self.config.flow
|
||||
}
|
||||
|
||||
fn echo_pkce_in_token_exchange(&self) -> bool {
|
||||
self.config.echo_pkce_in_token_exchange
|
||||
}
|
||||
|
||||
fn include_state_in_token_exchange(&self) -> bool {
|
||||
self.config.include_state_in_token_exchange
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,8 @@ impl OAuthProvider for OpenAIOAuthProvider {
|
||||
"http://localhost:1455/auth/callback"
|
||||
}
|
||||
|
||||
fn scopes(&self) -> &str {
|
||||
"openid profile email offline_access"
|
||||
fn scopes(&self) -> String {
|
||||
"openid profile email offline_access".to_string()
|
||||
}
|
||||
|
||||
fn token_request_format(&self) -> TokenRequestFormat {
|
||||
|
||||
+2
-2
@@ -61,8 +61,8 @@ impl OAuthProvider for McpOAuthProvider {
|
||||
""
|
||||
}
|
||||
|
||||
fn scopes(&self) -> &str {
|
||||
&self.scopes
|
||||
fn scopes(&self) -> String {
|
||||
self.scopes.clone()
|
||||
}
|
||||
|
||||
fn token_request_format(&self) -> TokenRequestFormat {
|
||||
|
||||
Reference in New Issue
Block a user