feat: Implemented OAuth support for OpenAI models via Codex endpoints
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
use super::oauth::{OAuthProvider, TokenRequestFormat};
|
||||
use base64::Engine;
|
||||
use base64::engine::general_purpose::URL_SAFE_NO_PAD;
|
||||
use serde_json::Value;
|
||||
|
||||
pub struct OpenAIOAuthProvider;
|
||||
|
||||
impl OAuthProvider for OpenAIOAuthProvider {
|
||||
fn provider_name(&self) -> &str {
|
||||
"openai"
|
||||
}
|
||||
|
||||
fn client_id(&self) -> &str {
|
||||
"app_EMoamEEZ73f0CkXaXp7hrann"
|
||||
}
|
||||
|
||||
fn authorize_url(&self) -> &str {
|
||||
"https://auth.openai.com/oauth/authorize"
|
||||
}
|
||||
|
||||
fn token_url(&self) -> &str {
|
||||
"https://auth.openai.com/oauth/token"
|
||||
}
|
||||
|
||||
fn redirect_uri(&self) -> &str {
|
||||
"http://localhost:1455/auth/callback"
|
||||
}
|
||||
|
||||
fn scopes(&self) -> &str {
|
||||
"openid profile email offline_access"
|
||||
}
|
||||
|
||||
fn token_request_format(&self) -> TokenRequestFormat {
|
||||
TokenRequestFormat::FormUrlEncoded
|
||||
}
|
||||
|
||||
fn extra_authorize_params(&self) -> Vec<(&str, &str)> {
|
||||
vec![
|
||||
("id_token_add_organizations", "true"),
|
||||
("codex_cli_simplified_flow", "true"),
|
||||
]
|
||||
}
|
||||
|
||||
fn fixed_redirect_uri(&self) -> Option<String> {
|
||||
Some("http://localhost:1455/auth/callback".to_string())
|
||||
}
|
||||
|
||||
fn include_state_in_token_exchange(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn extract_account_id(&self, response: &Value) -> Option<String> {
|
||||
let id_token = response["id_token"].as_str().unwrap_or_default();
|
||||
let access_token = response["access_token"].as_str().unwrap_or_default();
|
||||
extract_account_id_from_jwt(id_token).or_else(|| extract_account_id_from_jwt(access_token))
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_account_id_from_jwt(token: &str) -> Option<String> {
|
||||
let parts: Vec<&str> = token.splitn(3, '.').collect();
|
||||
if parts.len() < 2 {
|
||||
return None;
|
||||
}
|
||||
let decoded = URL_SAFE_NO_PAD.decode(parts[1]).ok()?;
|
||||
let claims: Value = serde_json::from_slice(&decoded).ok()?;
|
||||
claims["chatgpt_account_id"]
|
||||
.as_str()
|
||||
.map(|s| s.to_string())
|
||||
.or_else(|| {
|
||||
claims["https://api.openai.com/auth"]["chatgpt_account_id"]
|
||||
.as_str()
|
||||
.map(|s| s.to_string())
|
||||
})
|
||||
.or_else(|| {
|
||||
claims["organizations"][0]["id"]
|
||||
.as_str()
|
||||
.map(|s| s.to_string())
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user