Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
44d0cc5
Add Apple identity type to primitives
silva-fj Oct 15, 2025
34e9074
Add Apple OAuth2 configuration infrastructure
silva-fj Oct 15, 2025
d400b2e
Add Apple OAuth2 client and helpers
silva-fj Oct 15, 2025
d35681e
Refactor OAuth2 RPC methods to support Apple
silva-fj Oct 15, 2025
e709d21
Add Apple OAuth2 verification logic
silva-fj Oct 15, 2025
7fbfb51
Add Copy trait to OAuth2Provider enum
silva-fj Oct 15, 2025
f56536e
Refactor OAuth2 configuration to eliminate duplication
silva-fj Oct 15, 2025
92b067e
Create unified OAuth2Client and provider config trait
silva-fj Oct 15, 2025
e2054ae
Create shared OAuth2 authorization helpers
silva-fj Oct 15, 2025
ed03da0
Replace separate factories with unified OAuth2ConfigFactory
silva-fj Oct 15, 2025
c4cf695
Unify OAuth2 verification logic into single function
silva-fj Oct 15, 2025
32488c1
Simplify RPC layer with unified OAuth2 factory
silva-fj Oct 15, 2025
42e3656
feat(identity): add Apple variant to token conversion
silva-fj Oct 15, 2025
10789bb
Add Apple identity variant support to identity worker
silva-fj Oct 15, 2025
ada7a5d
Add Apple variant to parachain identity tests
silva-fj Oct 15, 2025
a087cc3
fix(auth): use correct token type for OAuth2 login
silva-fj Oct 16, 2025
fbbf7e5
Extract shared JWT token decoding to oauth2_common
silva-fj Oct 16, 2025
db2ae00
feat(oauth2): add nonce to OAuth2 verification flow
silva-fj Oct 16, 2025
715a0f8
fix(oauth2): correct IdToken field types for Google and Apple
silva-fj Oct 16, 2025
e9f6dcb
refactor(oauth2): add OAuth2ProviderConfig helper
silva-fj Oct 16, 2025
76ed5d3
refactor(rpc): rename OAuth2 authorization method and return data object
silva-fj Oct 16, 2025
2b674f9
feat(oauth2): verify id_token with nonce and audience checks
silva-fj Oct 16, 2025
128c38e
fix(oauth2): change Google IdToken email_verified to bool type
silva-fj Oct 17, 2025
d07a946
refactor(oauth2): make redirect_uri optional in OAuth2Data
silva-fj Oct 20, 2025
2014786
refactor(oauth2): make redirect_uri optional in helper functions
silva-fj Oct 20, 2025
c7b31e7
refactor(oauth2): make redirect_uri optional in RPC methods
silva-fj Oct 20, 2025
cd17de0
Merge branch 'dev' into p-1707-login-with-apple
BillyWooo Oct 20, 2025
862ec8d
test(oauth2): fix tests for optional redirect_uri
silva-fj Oct 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions parachain/primitives/src/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,9 @@ pub enum Identity {

#[codec(index = 10)]
Passkey(IdentityString),

#[codec(index = 11)]
Apple(IdentityString),
}

impl Identity {
Expand All @@ -348,6 +351,7 @@ impl Identity {
| Self::Google(..)
| Self::Pumpx(..)
| Self::Passkey(..)
| Self::Apple(..)
)
}

Expand Down Expand Up @@ -383,7 +387,8 @@ impl Identity {
| Identity::Email(_)
| Identity::Google(_)
| Identity::Pumpx(_)
| Identity::Passkey(_) => Vec::new(),
| Identity::Passkey(_)
| Identity::Apple(_) => Vec::new(),
}
}

Expand All @@ -402,7 +407,8 @@ impl Identity {
| Identity::Email(_)
| Identity::Google(_)
| Identity::Pumpx(_)
| Identity::Passkey(_) => networks.is_empty(),
| Identity::Passkey(_)
| Identity::Apple(_) => networks.is_empty(),
}
}

Expand All @@ -425,6 +431,7 @@ impl Identity {
| Identity::Github(_)
| Identity::Email(_)
| Identity::Google(_)
| Identity::Apple(_)
| Identity::Pumpx(_)
| Identity::Passkey(_) => None,
}
Expand Down Expand Up @@ -484,6 +491,10 @@ impl Identity {
hasher.update(b"google");
hasher.update(String::from_utf8(handle.inner.to_vec()).unwrap_or_default());
},
Identity::Apple(handle) => {
hasher.update(b"apple");
hasher.update(String::from_utf8(handle.inner.to_vec()).unwrap_or_default());
},
Identity::Pumpx(handle) => {
// TODO: this type will be removed.
hasher.update(b"pumpx");
Expand Down Expand Up @@ -592,6 +603,11 @@ impl Identity {
str::from_utf8(handle.inner_ref())
.map_err(|_| "google handle conversion error")?
),
Identity::Apple(handle) => format!(
"apple:{}",
str::from_utf8(handle.inner_ref())
.map_err(|_| "apple handle conversion error")?
),
Identity::Pumpx(handle) => format!(
"pumpx:{}",
str::from_utf8(handle.inner_ref())
Expand Down Expand Up @@ -627,6 +643,9 @@ impl Identity {
Web2IdentityType::Google => {
Identity::Google(IdentityString::new(handle.as_bytes().to_vec()))
},
Web2IdentityType::Apple => {
Identity::Apple(IdentityString::new(handle.as_bytes().to_vec()))
},
Web2IdentityType::Pumpx => {
Identity::Pumpx(IdentityString::new(handle.as_bytes().to_vec()))
},
Expand All @@ -641,6 +660,7 @@ pub enum Web2IdentityType {
Github,
Email,
Google,
Apple,
Pumpx,
}

Expand Down Expand Up @@ -720,6 +740,7 @@ mod tests {
Identity::Bitcoin(..) => false,
Identity::Solana(..) => false,
Identity::Google(..) => true,
Identity::Apple(..) => true,
Identity::Pumpx(..) => true,
Identity::Passkey(..) => true,
}
Expand All @@ -742,6 +763,7 @@ mod tests {
Identity::Bitcoin(..) => true,
Identity::Solana(..) => true,
Identity::Google(..) => false,
Identity::Apple(..) => false,
Identity::Pumpx(..) => false,
Identity::Passkey(..) => false,
}
Expand All @@ -764,6 +786,7 @@ mod tests {
Identity::Bitcoin(..) => false,
Identity::Solana(..) => false,
Identity::Google(..) => false,
Identity::Apple(..) => false,
Identity::Pumpx(..) => false,
Identity::Passkey(..) => false,
}
Expand All @@ -786,6 +809,7 @@ mod tests {
Identity::Bitcoin(..) => false,
Identity::Solana(..) => false,
Identity::Google(..) => false,
Identity::Apple(..) => false,
Identity::Pumpx(..) => false,
Identity::Passkey(..) => false,
}
Expand All @@ -808,6 +832,7 @@ mod tests {
Identity::Bitcoin(..) => true,
Identity::Solana(..) => false,
Identity::Google(..) => false,
Identity::Apple(..) => false,
Identity::Pumpx(..) => false,
Identity::Passkey(..) => false,
}
Expand All @@ -830,6 +855,7 @@ mod tests {
Identity::Bitcoin(..) => false,
Identity::Solana(..) => true,
Identity::Google(..) => false,
Identity::Apple(..) => false,
Identity::Pumpx(..) => false,
Identity::Passkey(..) => false,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ pub fn identity_with_networks_to_token(identity: &IdentityNetworkTuple) -> Token
Identity::Google(str) => (8, str.inner_ref().to_vec()),
Identity::Pumpx(str) => (9, str.inner_ref().to_vec()),
Identity::Passkey(str) => (10, str.inner_ref().to_vec()),
Identity::Apple(str) => (11, str.inner_ref().to_vec()),
};
let networks: Vec<Token> = identity.1.iter().map(network_to_token).collect();
Token::Tuple(vec![Token::Uint(type_index.into()), Token::Bytes(value), Token::Array(networks)])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use sp_core::{blake2_256, crypto::AccountId32 as AccountId, H256};
#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq)]
pub enum OAuth2Provider {
Google,
Apple,
}

#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -100,6 +101,9 @@ pub fn verify_tca_oauth2_authentication(
OAuth2Provider::Google => {
verify_google_oauth2(data_providers_config, sender_identity_hash, omni_account, payload)
},
OAuth2Provider::Apple => Err(AuthenticationError::OAuth2Error(String::from(
"Apple OAuth2 not yet supported in identity worker",
))),
}
}

Expand Down
1 change: 1 addition & 0 deletions tee-worker/identity/service/src/prometheus_metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ fn handle_stf_call_request(req: RequestType, time: f64) {
Identity::Bitcoin(_) => "Bitcoin".into(),
Identity::Solana(_) => "Solana".into(),
Identity::Google(_) => "Google".into(),
Identity::Apple(_) => "Apple".into(),
Identity::Pumpx(_) => "Pumpx".into(),
Identity::Passkey(_) => "Passkey".into(),
},
Expand Down
108 changes: 64 additions & 44 deletions tee-worker/omni-executor/config-loader/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ impl Default for MailerConfig {
}

#[derive(Debug, Clone)]
pub struct GoogleOAuth2Config {
pub struct OAuth2Config {
pub client_id: String,
pub client_secret: String,
}

#[derive(Debug, Clone)]
pub struct ConfigLoader {
pub mailer_configs: HashMap<String, MailerConfig>,
pub google_oauth2_configs: HashMap<String, GoogleOAuth2Config>,
pub oauth2_configs: HashMap<String, HashMap<String, OAuth2Config>>, // client -> provider -> config
pub ethereum_url: String,
pub solana_url: String,
pub bsc_url: String,
Expand Down Expand Up @@ -335,11 +335,11 @@ impl ConfigLoader {
let get_opt = |key: &str| get_env_value(&vars[key]);

let mailer_configs = Self::load_mailer_configs();
let google_oauth2_configs = Self::load_google_oauth2_configs();
let oauth2_configs = Self::load_oauth2_configs();

ConfigLoader {
mailer_configs,
google_oauth2_configs,
oauth2_configs,
ethereum_url: append_key(&get("ethereum_url")),
solana_url: append_key(&get("solana_url")),
bsc_url: append_key(&get("bsc_url")),
Expand Down Expand Up @@ -452,62 +452,82 @@ impl ConfigLoader {
clients
}

/// Load Google OAuth2 configurations for multiple clients from environment variables
/// Format: OE_GOOGLE_CLIENT_ID_{CLIENT}, OE_GOOGLE_CLIENT_SECRET_{CLIENT}
/// Load OAuth2 configurations for all supported providers from environment variables
/// Format: OE_{PROVIDER}_CLIENT_ID_{CLIENT}, OE_{PROVIDER}_CLIENT_SECRET_{CLIENT}
/// PROVIDER can be GOOGLE, APPLE, etc.
/// CLIENT can be WILDMETA, HEIMA, etc.
fn load_google_oauth2_configs() -> HashMap<String, GoogleOAuth2Config> {
let mut configs = HashMap::new();

let env_vars: HashMap<String, String> = std::env::vars().collect();

let mut clients = std::collections::HashSet::new();
for key in env_vars.keys() {
if key.starts_with("OE_GOOGLE_CLIENT_ID_") {
if let Some(client) = key.strip_prefix("OE_GOOGLE_CLIENT_ID_") {
info!("Found Google OAuth2 configuration for client: {}", client);
clients.insert(client.to_lowercase());
fn load_oauth2_configs() -> HashMap<String, HashMap<String, OAuth2Config>> {
let providers = vec!["GOOGLE", "APPLE"];
let mut all_configs: HashMap<String, HashMap<String, OAuth2Config>> = HashMap::new();

for provider in providers {
let provider_lower = provider.to_lowercase();
let prefix = format!("OE_{}_CLIENT_ID_", provider);

let env_vars: HashMap<String, String> = std::env::vars().collect();
let mut clients = std::collections::HashSet::new();

for key in env_vars.keys() {
if key.starts_with(&prefix) {
if let Some(client) = key.strip_prefix(&prefix) {
info!(
"Found {} OAuth2 configuration for client: {}",
provider_lower, client
);
clients.insert(client.to_lowercase());
}
}
}
}

info!("Total discovered Google OAuth2 clients: {:?}", clients);
info!("Total discovered {} OAuth2 clients: {:?}", provider_lower, clients);

if clients.is_empty() {
warn!("No Google OAuth2 configurations found in environment variables.");
return configs;
}

for client in clients {
let client_upper = client.to_uppercase();

let client_id =
std::env::var(format!("OE_GOOGLE_CLIENT_ID_{}", client_upper)).unwrap_or_default();
let client_secret = std::env::var(format!("OE_GOOGLE_CLIENT_SECRET_{}", client_upper))
.unwrap_or_default();

if client_id.is_empty() || client_secret.is_empty() {
if clients.is_empty() {
warn!(
"Incomplete Google OAuth2 config for client '{}': client_id_empty={}, client_secret_empty={}",
client,
client_id.is_empty(),
client_secret.is_empty()
"No {} OAuth2 configurations found in environment variables.",
provider_lower
);
continue;
}

let config = GoogleOAuth2Config { client_id, client_secret };
for client in clients {
let client_upper = client.to_uppercase();

let client_id =
std::env::var(format!("OE_{}_CLIENT_ID_{}", provider, client_upper))
.unwrap_or_default();
let client_secret =
std::env::var(format!("OE_{}_CLIENT_SECRET_{}", provider, client_upper))
.unwrap_or_default();

if client_id.is_empty() || client_secret.is_empty() {
warn!(
"Incomplete {} OAuth2 config for client '{}': client_id_empty={}, client_secret_empty={}",
provider_lower,
client,
client_id.is_empty(),
client_secret.is_empty()
);
continue;
}

info!("Loaded Google OAuth2 config for client '{}'", client);
let config = OAuth2Config { client_id, client_secret };

configs.insert(client.clone(), config);
info!("Loaded {} OAuth2 config for client '{}'", provider_lower, client);

all_configs
.entry(client.clone())
.or_default()
.insert(provider_lower.clone(), config);
}
}

configs
all_configs
}

/// Get Google OAuth2 configuration for a specific client
pub fn get_google_oauth2_config(&self, client_id: &str) -> Option<GoogleOAuth2Config> {
/// Get OAuth2 configuration for a specific client and provider
pub fn get_oauth2_config(&self, client_id: &str, provider: &str) -> Option<OAuth2Config> {
let client_key = client_id.to_lowercase();
self.google_oauth2_configs.get(&client_key).cloned()
let provider_key = provider.to_lowercase();
self.oauth2_configs.get(&client_key)?.get(&provider_key).cloned()
}
}
2 changes: 1 addition & 1 deletion tee-worker/omni-executor/config-loader/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
mod config;

pub use config::{ConfigLoader, GoogleOAuth2Config, MailerConfig, MailerType};
pub use config::{ConfigLoader, MailerConfig, MailerType, OAuth2Config};
Loading
Loading