Skip to content

Commit 76e7f15

Browse files
committed
fix(wallet): route OIDC requests through wallet transport
1 parent a6e580b commit 76e7f15

17 files changed

Lines changed: 555 additions & 178 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cdk-cli/src/main.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -302,12 +302,7 @@ async fn main() -> Result<()> {
302302
sub_commands::check_requests::check_requests(&wallet_repository).await
303303
}
304304
Commands::MintInfo(sub_command_args) => {
305-
sub_commands::mint_info::mint_info(
306-
args.proxy,
307-
args.danger_accept_invalid_certs,
308-
sub_command_args,
309-
)
310-
.await
305+
sub_commands::mint_info::mint_info(&wallet_repository, sub_command_args).await
311306
}
312307
Commands::Mint(sub_command_args) => {
313308
sub_commands::mint::mint(&wallet_repository, sub_command_args, &default_unit).await

crates/cdk-cli/src/sub_commands/cat_device_login.rs

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use anyhow::Result;
55
use cdk::mint_url::MintUrl;
66
use cdk::nuts::MintInfo;
77
use cdk::wallet::WalletRepository;
8-
use cdk::OidcClient;
98
use clap::Args;
109
use serde::{Deserialize, Serialize};
1110
use tokio::time::sleep;
@@ -32,7 +31,8 @@ pub async fn cat_device_login(
3231

3332
let mint_info = wallet_repository.fetch_mint_info(&mint_url).await?;
3433

35-
let (access_token, refresh_token) = get_device_code_token(&mint_info).await;
34+
let (access_token, refresh_token) =
35+
get_device_code_token(wallet_repository, &mint_url, &mint_info).await?;
3636

3737
// Save tokens to file in work directory
3838
if let Err(e) =
@@ -52,56 +52,57 @@ pub async fn cat_device_login(
5252
Ok(())
5353
}
5454

55-
async fn get_device_code_token(mint_info: &MintInfo) -> (String, String) {
55+
async fn get_device_code_token(
56+
wallet_repository: &WalletRepository,
57+
mint_url: &MintUrl,
58+
mint_info: &MintInfo,
59+
) -> Result<(String, String)> {
5660
let openid_discovery = mint_info
5761
.nuts
5862
.nut21
5963
.clone()
60-
.expect("Nut21 defined")
64+
.ok_or_else(|| anyhow::anyhow!("NUT-21 OIDC settings are not defined"))?
6165
.openid_discovery;
6266

6367
let client_id = mint_info
6468
.nuts
6569
.nut21
6670
.clone()
67-
.expect("Nut21 defined")
71+
.ok_or_else(|| anyhow::anyhow!("NUT-21 OIDC settings are not defined"))?
6872
.client_id;
6973

70-
let oidc_client = OidcClient::new(openid_discovery, None);
74+
let oidc_client = wallet_repository
75+
.oidc_client_for_mint(mint_url, openid_discovery, None)
76+
.await;
7177

7278
// Get the OIDC configuration
73-
let oidc_config = oidc_client
74-
.get_oidc_config()
75-
.await
76-
.expect("Failed to get OIDC config");
79+
let oidc_config = oidc_client.get_oidc_config().await?;
7780

7881
// Get the device authorization endpoint
7982
let device_auth_url = oidc_config.device_authorization_endpoint;
8083

8184
// Make the device code request
82-
let client = cdk_common::HttpClient::new();
83-
let device_code_data: serde_json::Value = client
85+
let device_code_data: serde_json::Value = oidc_client
8486
.post_form(
8587
&device_auth_url,
86-
&[
87-
("client_id", client_id.clone().as_str()),
88-
("scope", "openid offline_access"),
88+
vec![
89+
("client_id".to_string(), client_id.clone()),
90+
("scope".to_string(), "openid offline_access".to_string()),
8991
],
9092
)
91-
.await
92-
.expect("Failed to send device code request");
93+
.await?;
9394

9495
let device_code = device_code_data["device_code"]
9596
.as_str()
96-
.expect("No device code in response");
97+
.ok_or_else(|| anyhow::anyhow!("No device code in response"))?;
9798

9899
let user_code = device_code_data["user_code"]
99100
.as_str()
100-
.expect("No user code in response");
101+
.ok_or_else(|| anyhow::anyhow!("No user code in response"))?;
101102

102103
let verification_uri = device_code_data["verification_uri"]
103104
.as_str()
104-
.expect("No verification URI in response");
105+
.ok_or_else(|| anyhow::anyhow!("No verification URI in response"))?;
105106

106107
let verification_uri_complete = device_code_data["verification_uri_complete"]
107108
.as_str()
@@ -122,39 +123,37 @@ async fn get_device_code_token(mint_info: &MintInfo) -> (String, String) {
122123
loop {
123124
sleep(Duration::from_secs(interval)).await;
124125

125-
let token_response = client
126-
.post(&token_url)
127-
.form(&[
128-
("grant_type", "urn:ietf:params:oauth:grant-type:device_code"),
129-
("device_code", device_code),
130-
("client_id", client_id.clone().as_str()),
131-
])
132-
.send()
133-
.await
134-
.expect("Failed to send token request");
126+
let token_response = oidc_client
127+
.post_form_response(
128+
&token_url,
129+
vec![
130+
(
131+
"grant_type".to_string(),
132+
"urn:ietf:params:oauth:grant-type:device_code".to_string(),
133+
),
134+
("device_code".to_string(), device_code.to_string()),
135+
("client_id".to_string(), client_id.clone()),
136+
],
137+
)
138+
.await?;
135139

136140
if token_response.is_success() {
137-
let token_data: serde_json::Value = token_response
138-
.json()
139-
.await
140-
.expect("Failed to parse token response");
141+
let token_data: serde_json::Value = token_response.json()?;
141142

142143
let access_token = token_data["access_token"]
143144
.as_str()
144-
.expect("No access token in response")
145+
.ok_or_else(|| anyhow::anyhow!("No access token in response"))?
145146
.to_string();
146147

147148
let refresh_token = token_data["refresh_token"]
148149
.as_str()
149-
.expect("No refresh token in response")
150+
.ok_or_else(|| anyhow::anyhow!("No refresh token in response"))?
150151
.to_string();
151152

152-
return (access_token, refresh_token);
153+
return Ok((access_token, refresh_token));
153154
} else {
154-
let error_data: serde_json::Value = token_response
155-
.json()
156-
.await
157-
.expect("Failed to parse error response");
155+
let status = token_response.status();
156+
let error_data: serde_json::Value = token_response.json()?;
158157

159158
let error = error_data["error"].as_str().unwrap_or("unknown_error");
160159

@@ -168,7 +167,11 @@ async fn get_device_code_token(mint_info: &MintInfo) -> (String, String) {
168167
continue;
169168
} else {
170169
// For other errors, exit with an error message
171-
panic!("Authentication failed: {error}");
170+
return Err(anyhow::anyhow!(
171+
"Authentication failed with status {}: {}",
172+
status,
173+
error
174+
));
172175
}
173176
}
174177
}

crates/cdk-cli/src/sub_commands/cat_login.rs

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use anyhow::Result;
44
use cdk::mint_url::MintUrl;
55
use cdk::nuts::MintInfo;
66
use cdk::wallet::WalletRepository;
7-
use cdk::OidcClient;
87
use clap::Args;
98
use serde::{Deserialize, Serialize};
109

@@ -35,11 +34,13 @@ pub async fn cat_login(
3534
let mint_info = wallet_repository.fetch_mint_info(&mint_url).await?;
3635

3736
let (access_token, refresh_token) = get_access_token(
37+
wallet_repository,
38+
&mint_url,
3839
&mint_info,
3940
&sub_command_args.username,
4041
&sub_command_args.password,
4142
)
42-
.await;
43+
.await?;
4344

4445
// Save tokens to file in work directory
4546
if let Err(e) =
@@ -58,55 +59,55 @@ pub async fn cat_login(
5859
Ok(())
5960
}
6061

61-
async fn get_access_token(mint_info: &MintInfo, user: &str, password: &str) -> (String, String) {
62+
async fn get_access_token(
63+
wallet_repository: &WalletRepository,
64+
mint_url: &MintUrl,
65+
mint_info: &MintInfo,
66+
user: &str,
67+
password: &str,
68+
) -> Result<(String, String)> {
6269
let openid_discovery = mint_info
6370
.nuts
6471
.nut21
6572
.clone()
66-
.expect("Nut21 defined")
73+
.ok_or_else(|| anyhow::anyhow!("NUT-21 OIDC settings are not defined"))?
6774
.openid_discovery;
6875

6976
let client_id = mint_info
7077
.nuts
7178
.nut21
7279
.clone()
73-
.expect("Nut21 defined")
80+
.ok_or_else(|| anyhow::anyhow!("NUT-21 OIDC settings are not defined"))?
7481
.client_id;
7582

76-
let oidc_client = OidcClient::new(openid_discovery, None);
83+
let oidc_client = wallet_repository
84+
.oidc_client_for_mint(mint_url, openid_discovery, None)
85+
.await;
7786

7887
// Get the token endpoint from the OIDC configuration
79-
let token_url = oidc_client
80-
.get_oidc_config()
81-
.await
82-
.expect("Failed to get OIDC config")
83-
.token_endpoint;
88+
let token_url = oidc_client.get_oidc_config().await?.token_endpoint;
8489

8590
// Create the request parameters
86-
let params = [
87-
("grant_type", "password"),
88-
("client_id", &client_id),
89-
("scope", "openid offline_access"),
90-
("username", user),
91-
("password", password),
91+
let params = vec![
92+
("grant_type".to_string(), "password".to_string()),
93+
("client_id".to_string(), client_id),
94+
("scope".to_string(), "openid offline_access".to_string()),
95+
("username".to_string(), user.to_string()),
96+
("password".to_string(), password.to_string()),
9297
];
9398

9499
// Make the token request directly
95-
let client = cdk_common::HttpClient::new();
96-
let token_response: serde_json::Value = client
97-
.post_form(&token_url, &params)
98-
.await
99-
.expect("Failed to send token request");
100+
let token_response: serde_json::Value = oidc_client.post_form(&token_url, params).await?;
100101

101102
let access_token = token_response["access_token"]
102103
.as_str()
103-
.expect("No access token in response")
104+
.ok_or_else(|| anyhow::anyhow!("No access token in response"))?
104105
.to_string();
105106

106107
let refresh_token = token_response["refresh_token"]
107108
.as_str()
108-
.expect("No refresh token in response")
109+
.ok_or_else(|| anyhow::anyhow!("No refresh token in response"))?
109110
.to_string();
110111

111-
(access_token, refresh_token)
112+
Ok((access_token, refresh_token))
112113
}

crates/cdk-cli/src/sub_commands/mint_blind_auth.rs

Lines changed: 17 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use anyhow::{anyhow, Result};
44
use cdk::mint_url::MintUrl;
55
use cdk::nuts::{CurrencyUnit, MintInfo};
66
use cdk::wallet::WalletRepository;
7-
use cdk::{Amount, OidcClient};
7+
use cdk::{Amount, Wallet};
88
use clap::Args;
99
use serde::{Deserialize, Serialize};
1010

@@ -75,7 +75,7 @@ pub async fn mint_blind_auth(
7575

7676
// Get the mint info to access OIDC configuration
7777
let mint_info = wallet_repository.fetch_mint_info(&mint_url).await?;
78-
match refresh_access_token(&mint_info, &token_data.refresh_token).await {
78+
match refresh_access_token(&wallet, &mint_info, &token_data.refresh_token).await {
7979
Ok((new_access_token, new_refresh_token)) => {
8080
println!("Successfully refreshed access token");
8181

@@ -141,51 +141,27 @@ pub async fn mint_blind_auth(
141141
}
142142

143143
async fn refresh_access_token(
144+
wallet: &Wallet,
144145
mint_info: &MintInfo,
145146
refresh_token: &str,
146147
) -> Result<(String, String)> {
147148
let openid_discovery = mint_info
148-
.nuts
149-
.nut21
150-
.clone()
151-
.ok_or_else(|| anyhow::anyhow!("OIDC discovery information not available"))?
152-
.openid_discovery;
153-
154-
let oidc_client = OidcClient::new(openid_discovery, None);
155-
156-
// Get the token endpoint from the OIDC configuration
157-
let token_url = oidc_client.get_oidc_config().await?.token_endpoint;
158-
159-
// Create the request parameters for token refresh
160-
let params = [
161-
("grant_type", "refresh_token"),
162-
("refresh_token", refresh_token),
163-
("client_id", "cashu-client"), // Using default client ID
164-
];
165-
166-
// Make the token refresh request
167-
let client = cdk_common::HttpClient::new();
168-
let response = client.post(&token_url).form(&params).send().await?;
169-
170-
if !response.is_success() {
171-
return Err(anyhow::anyhow!(
172-
"Token refresh failed with status: {}",
173-
response.status()
174-
));
175-
}
176-
177-
let token_response: serde_json::Value = response.json().await?;
178-
179-
let access_token = token_response["access_token"]
180-
.as_str()
181-
.ok_or_else(|| anyhow::anyhow!("No access token in refresh response"))?
182-
.to_string();
149+
.openid_discovery()
150+
.ok_or_else(|| anyhow::anyhow!("OIDC discovery information not available"))?;
151+
let client_id = mint_info
152+
.client_id()
153+
.ok_or_else(|| anyhow::anyhow!("OIDC client ID is not available"))?;
154+
let oidc_client = wallet.oidc_client(openid_discovery, None);
155+
let token_response = oidc_client
156+
.refresh_access_token(client_id, refresh_token.to_string())
157+
.await?;
158+
159+
let access_token = token_response.access_token;
183160

184161
// Get the new refresh token or use the old one if not provided
185-
let new_refresh_token = token_response["refresh_token"]
186-
.as_str()
187-
.unwrap_or(refresh_token)
188-
.to_string();
162+
let new_refresh_token = token_response
163+
.refresh_token
164+
.unwrap_or_else(|| refresh_token.to_string());
189165

190166
Ok((access_token, new_refresh_token))
191167
}

0 commit comments

Comments
 (0)