MCPcopy Create free account
hub / github.com/NVIDIA/OpenShell / oidc_browser_auth_flow

Function oidc_browser_auth_flow

crates/openshell-cli/src/oidc_auth.rs:102–182  ·  view source on GitHub ↗

Run the OIDC Authorization Code + PKCE browser flow. Opens the user's browser to the Keycloak login page and waits for the authorization code redirect on a localhost callback server.

(
    issuer: &str,
    client_id: &str,
    audience: Option<&str>,
    scopes: Option<&str>,
    insecure: bool,
)

Source from the content-addressed store, hash-verified

100/// Opens the user's browser to the Keycloak login page and waits for
101/// the authorization code redirect on a localhost callback server.
102pub async fn oidc_browser_auth_flow(
103 issuer: &str,
104 client_id: &str,
105 audience: Option<&str>,
106 scopes: Option<&str>,
107 insecure: bool,
108) -> Result<OidcTokenBundle> {
109 let discovery = discover(issuer, insecure).await?;
110
111 let listener = TcpListener::bind("127.0.0.1:0").await.into_diagnostic()?;
112 let port = listener.local_addr().into_diagnostic()?.port();
113 let redirect_uri = format!("http://127.0.0.1:{port}/callback");
114
115 let client = BasicClient::new(ClientId::new(client_id.to_string()))
116 .set_auth_uri(AuthUrl::new(discovery.authorization_endpoint).into_diagnostic()?)
117 .set_token_uri(TokenUrl::new(discovery.token_endpoint).into_diagnostic()?)
118 .set_redirect_uri(RedirectUrl::new(redirect_uri).into_diagnostic()?);
119
120 let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256();
121
122 let mut auth_request = client
123 .authorize_url(CsrfToken::new_random)
124 .set_pkce_challenge(pkce_challenge);
125
126 for scope in build_scopes(scopes) {
127 auth_request = auth_request.add_scope(scope);
128 }
129
130 let (mut auth_url, csrf_token) = auth_request.url();
131
132 // Append audience parameter for providers like Entra ID where the API
133 // audience differs from the client ID.
134 if let Some(aud) = audience {
135 auth_url.query_pairs_mut().append_pair("audience", aud);
136 }
137
138 let (tx, rx) = oneshot::channel::<String>();
139 let expected_state = csrf_token.secret().clone();
140
141 let server_handle = tokio::spawn(run_oidc_callback_server(listener, tx, expected_state));
142
143 eprintln!(" Opening browser for OIDC authentication...");
144 if let Err(e) = crate::auth::open_browser_url(auth_url.as_str()) {
145 debug!(error = %e, "failed to open browser");
146 eprintln!("Could not open browser automatically.");
147 eprintln!("Open this URL in your browser:");
148 eprintln!(" {auth_url}");
149 eprintln!();
150 } else {
151 eprintln!(" Browser opened. Waiting for authentication...");
152 }
153
154 let code = tokio::select! {
155 result = rx => {
156 result.map_err(|_| miette::miette!("OIDC callback channel closed unexpectedly"))?
157 }
158 () = tokio::time::sleep(AUTH_TIMEOUT) => {
159 return Err(miette::miette!(

Callers 2

gateway_addFunction · 0.85
gateway_loginFunction · 0.85

Calls 9

discoverFunction · 0.85
build_scopesFunction · 0.85
run_oidc_callback_serverFunction · 0.85
open_browser_urlFunction · 0.85
http_clientFunction · 0.85
abortMethod · 0.80
spawnFunction · 0.50
as_strMethod · 0.45

Tested by

no test coverage detected