Crates.io | ones-oidc |
lib.rs | ones-oidc |
version | 0.3.2 |
created_at | 2025-01-31 21:13:45.662102+00 |
updated_at | 2025-08-09 22:39:46.75061+00 |
description | ONES OpenID Connect client for Rust |
homepage | https://ones-now.com/ |
repository | https://ones-now.com/ |
max_upload_size | |
id | 1537839 |
size | 168,125 |
Package to authenticate with ONES using OpenID Connect (OIDC) and Client Initiated Backchannel Authentication (CIBA).
use ones_oidc::{OpenIdconnectClient, load_device_config, read_private_key, OnesOidcConfig};
use openidconnect::{ClientId, IssuerUrl, core::CoreProviderMetadata, reqwest::async_http_client};
let device_config = load_device_config("./device.yml").expect("Failed to load device config");
let private_key = read_private_key("./device.key").expect("Failed to load private key");
let client_id = device_config.client_id.clone();
let issuer_url = device_config.get_issuer_url().expect("Failed to get issuer URL");
let provider_metadata = CoreProviderMetadata::discover_async(
issuer_url.clone(),
async_http_client,
)
.await
.expect("Failed to discover OIDC metadata");
// Create client with default configuration
let openid_client = OpenIdconnectClient::new(
client_id,
issuer_url,
provider_metadata,
private_key,
);
// Or create client with custom configuration
let config = OnesOidcConfig::default();
let openid_client = OpenIdconnectClient::with_config(
client_id,
issuer_url,
provider_metadata,
private_key,
config,
);
// Reuse the `openid_client` from the previous example
let device_access_token = openid_client.device_access_token().await
.expect("Failed to get device access token");
// Or use the non-cached version
let device_access_token = openid_client.request_device_access_token().await
.expect("Failed to request device access token");
Authenticate with user username (OnesID).
use ones_oidc::{LoginHint, LoginHintKind};
// Reuse the `openid_client` from the previous example
let login_hint = LoginHint {
kind: LoginHintKind::LoginHint,
value: "user@example.com".to_string(),
};
let result = openid_client.make_ciba_request(
&login_hint,
"openid offline_access profile",
"Authorize login to Example.com?",
Some("https://example.com".to_string()),
None, // qr_session_id
).await;
match result {
Ok(ciba_response) => {
println!("CIBA request successful: {:?}", ciba_response);
// Use ciba_response.auth_req_id for status polling
}
Err(e) => {
eprintln!("CIBA request failed: {}", e);
}
}
use ones_oidc::OidcError;
// Reuse the `openid_client` from the previous example
// Use the auth_req_id from the previous CIBA request
let auth_request_id = "your-auth-request-id";
match openid_client.check_ciba_status(auth_request_id).await {
Ok(ciba_status) => {
println!("CIBA Status: {:?}", ciba_status);
// Process the successful response
if let Some(access_token) = &ciba_status.access_token {
println!("Access token received: {}", access_token.secret());
}
}
Err(OidcError::CibaAuthenticationPending) => {
println!("Authorization pending - user hasn't approved yet");
// Continue polling
}
Err(e) => {
eprintln!("CIBA status check failed: {}", e);
}
}
// Reuse the `openid_client` from the previous example
let token = "your-jwt-or-opaque-token";
match openid_client.validate_token(&token, None).await {
Ok(auth_result) => {
println!("Token is valid!");
println!("Subject: {}", auth_result.sub);
println!("Issuer: {}", auth_result.iss);
if let Some(username) = &auth_result.username {
println!("Username: {}", username);
}
}
Err(e) => {
eprintln!("Token validation failed: {}", e);
}
}
The library includes a CLI tool for common operations:
Build the CLI tool:
cargo build --release --bin cli
./target/release/cli device access-token
./target/release/cli device config
./target/release/cli well-known <client-identifier>
./target/release/cli --device-config /path/to/device.yml --device-private-key /path/to/key.pem device access-token
./target/release/cli help
./target/release/cli device help