refactor(examples): Rename oidc_cli to oauth_cli

And update the docs.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This commit is contained in:
Kévin Commaille
2025-03-21 19:57:12 +01:00
committed by Andy Balaam
parent 94f0beec51
commit 29f6606d99
4 changed files with 37 additions and 66 deletions
Generated
+1 -1
View File
@@ -1542,7 +1542,7 @@ dependencies = [
]
[[package]]
name = "example-oidc-cli"
name = "example-oauth-cli"
version = "0.1.0"
dependencies = [
"anyhow",
@@ -120,14 +120,14 @@
//! # Examples
//!
//! Most methods have examples, there is also an example CLI application that
//! supports all the actions described here, in [`examples/oidc_cli`].
//! supports all the actions described here, in [`examples/oauth_cli`].
//!
//! [MSC3861]: https://github.com/matrix-org/matrix-spec-proposals/pull/3861
//! [areweoidcyet.com]: https://areweoidcyet.com/
//! [`ClientBuilder::handle_refresh_tokens()`]: crate::ClientBuilder::handle_refresh_tokens()
//! [`Error`]: ruma::api::client::error::Error
//! [`ErrorKind::UnknownToken`]: ruma::api::client::error::ErrorKind::UnknownToken
//! [`examples/oidc_cli`]: https://github.com/matrix-org/matrix-rust-sdk/tree/main/examples/oidc_cli
//! [`examples/oauth_cli`]: https://github.com/matrix-org/matrix-rust-sdk/tree/main/examples/oauth_cli
use std::{
borrow::Cow,
@@ -1,12 +1,12 @@
[package]
name = "example-oidc-cli"
name = "example-oauth-cli"
version = "0.1.0"
edition = "2021"
publish = false
license = "Apache-2.0"
[[bin]]
name = "example-oidc-cli"
name = "example-oauth-cli"
test = false
[dependencies]
@@ -44,13 +44,13 @@ use tokio::{fs, io::AsyncBufReadExt as _};
use url::Url;
/// A command-line tool to demonstrate the steps requiring an interaction with
/// an OpenID Connect provider for a Matrix client, using the Authorization Code
/// flow.
/// an OAuth 2.0 authorization server for a Matrix client, using the
/// Authorization Code flow.
///
/// You can test this against one of the servers from the OIDC playground:
/// <https://github.com/element-hq/oidc-playground>.
///
/// To use this, just run `cargo run -p example-oidc-cli`, and everything
/// To use this, just run `cargo run -p example-oauth-cli`, and everything
/// is interactive after that. You might want to set the `RUST_LOG` environment
/// variable to `warn` to reduce the noise in the logs. The program exits
/// whenever an unexpected error occurs.
@@ -64,14 +64,14 @@ async fn main() -> anyhow::Result<()> {
// The folder containing this example's data.
let data_dir =
dirs::data_dir().expect("no data_dir directory found").join("matrix_sdk/oidc_cli");
dirs::data_dir().expect("no data_dir directory found").join("matrix_sdk/oauth_cli");
// The file where the session is persisted.
let session_file = data_dir.join("session.json");
let cli = if session_file.exists() {
OidcCli::from_stored_session(session_file).await?
OAuthCli::from_stored_session(session_file).await?
} else {
OidcCli::new(&data_dir, session_file).await?
OAuthCli::new(&data_dir, session_file).await?
};
cli.run().await
@@ -104,29 +104,22 @@ struct ClientSession {
passphrase: String,
}
/// The data needed to restore an OpenID Connect session.
#[derive(Debug, Serialize, Deserialize)]
struct Credentials {
/// The client ID obtained after registration.
client_id: ClientId,
}
/// The full session to persist.
#[derive(Debug, Serialize, Deserialize)]
struct StoredSession {
/// The data to re-build the client.
client_session: ClientSession,
/// The OIDC user session.
/// The OAuth 2.0 user session.
user_session: UserSession,
/// The OIDC client credentials.
client_credentials: Credentials,
/// The OAuth 2.0 client ID.
client_id: ClientId,
}
/// An OpenID Connect CLI.
/// An OAuth 2.0 CLI.
#[derive(Clone, Debug)]
struct OidcCli {
struct OAuthCli {
/// The Matrix client.
client: Client,
@@ -137,7 +130,7 @@ struct OidcCli {
session_file: PathBuf,
}
impl OidcCli {
impl OAuthCli {
/// Create a new session by logging in.
async fn new(data_dir: &Path, session_file: PathBuf) -> anyhow::Result<Self> {
println!("No previous session found, logging in…");
@@ -151,22 +144,11 @@ impl OidcCli {
// Persist the session to reuse it later.
// This is not very secure, for simplicity. If the system provides a way of
// storing secrets securely, it should be used instead.
// Note that we could also build the user session from the login response.
let user_session =
cli.client.oauth().user_session().expect("A logged-in client should have a session");
// The client registration data should be persisted separately than the user
// session, to be reused for other sessions or user accounts with the same
// issuer.
// Also, client metadata should be persisted as it might change depending on
// the provider metadata.
let client_credentials = Credentials { client_id };
let serialized_session = serde_json::to_string(&StoredSession {
client_session,
user_session,
client_credentials,
})?;
let serialized_session =
serde_json::to_string(&StoredSession { client_session, user_session, client_id })?;
fs::write(&cli.session_file, serialized_session).await?;
println!("Session persisted in {}", cli.session_file.to_string_lossy());
@@ -176,9 +158,9 @@ impl OidcCli {
Ok(cli)
}
/// Register the OIDC client with the provider.
/// Register the OAuth 2.0 client with the authorization server.
///
/// Returns the ID of the client returned by the provider.
/// Returns the ID of the client returned by the server.
async fn register_client(&self) -> anyhow::Result<ClientId> {
let oauth = self.client.oauth();
@@ -193,21 +175,14 @@ impl OidcCli {
);
}
let metadata = client_metadata();
// During registration, we have the option of providing a software statement,
// which is a digitally signed version of the client metadata. That would allow
// to update the metadata later without changing the client ID, but requires to
// have a way to serve public keys online to validate the signature of
// the JWT.
let res = oauth.register_client(&metadata).await?;
let res = oauth.register_client(&client_metadata()).await?;
println!("\nRegistered successfully");
Ok(res.client_id)
}
/// Login via the OIDC Authorization Code flow.
/// Login via the OAuth 2.0 Authorization Code flow.
async fn login(&self) -> anyhow::Result<()> {
let oauth = self.client.oauth();
@@ -247,7 +222,7 @@ impl OidcCli {
// The session was serialized as JSON in a file.
let serialized_session = fs::read_to_string(&session_file).await?;
let StoredSession { client_session, user_session, client_credentials } =
let StoredSession { client_session, user_session, client_id } =
serde_json::from_str(&serialized_session)?;
// Build the client with the previous settings from the session.
@@ -260,7 +235,7 @@ impl OidcCli {
println!("Restoring session for {}", user_session.meta.user_id);
let session = OAuthSession { client_id: client_credentials.client_id, user: user_session };
let session = OAuthSession { client_id, user: user_session };
// Restore the Matrix user session.
client.restore_session(session).await?;
@@ -370,7 +345,9 @@ impl OidcCli {
if let Some(handle) = encryption.reset_cross_signing().await? {
match handle.auth_type() {
CrossSigningResetAuthType::Uiaa(_) => {
unimplemented!("This should never happen, this is after all the OIDC example.")
unimplemented!(
"This should never happen, this is after all the OAuth 2.0 example."
)
}
CrossSigningResetAuthType::OAuth(o) => {
println!(
@@ -396,12 +373,12 @@ impl OidcCli {
let user_id = client.user_id().expect("A logged in client has a user ID");
let device_id = client.device_id().expect("A logged in client has a device ID");
let homeserver = client.homeserver();
let issuer = oauth.issuer().expect("A logged in OIDC client has an issuer");
let issuer = oauth.issuer().expect("A logged in OAuth 2.0 client has an issuer");
println!("\nUser ID: {user_id}");
println!("Device ID: {device_id}");
println!("Homeserver URL: {homeserver}");
println!("OpenID Connect provider: {issuer}");
println!("OAuth 2.0 authorization server: {issuer}");
}
/// Get the account management URL.
@@ -598,8 +575,7 @@ impl OidcCli {
/// Build a new client.
///
/// Returns the client, the data required to restore the client, and the OIDC
/// issuer advertised by the homeserver.
/// Returns the client and the data required to restore the client.
async fn build_client(data_dir: &Path) -> anyhow::Result<(Client, ClientSession)> {
let db_path = data_dir.join("db");
@@ -679,12 +655,7 @@ async fn build_client(data_dir: &Path) -> anyhow::Result<(Client, ClientSession)
}
}
/// Generate the OIDC client metadata.
///
/// For simplicity, we use most of the default values here, but usually this
/// should be adapted to the provider metadata to make interactions as secure as
/// possible, for example by using the most secure signing algorithms supported
/// by the provider.
/// Generate the OAuth 2.0 client metadata.
fn client_metadata() -> Raw<ClientMetadata> {
// Native clients should be able to register the IPv4 and IPv6 loopback
// interfaces and then point to any port when needing a redirect URI. An
@@ -700,11 +671,11 @@ fn client_metadata() -> Raw<ClientMetadata> {
);
let metadata = ClientMetadata {
// The following fields should be displayed in the OIDC provider interface as part of the
// process to get the user's consent. It means that these should contain real data so the
// user can make sure that they allow the proper application.
// We are cheating here because this is an example.
client_name: Some(Localized::new("matrix-rust-sdk-oidc-cli".to_owned(), [])),
// The following fields should be displayed in the OAuth 2.0 authorization server's
// web UI as part of the process to get the user's consent. It means that these
// should contain real data so the user can make sure that they allow the proper
// application. We are cheating here because this is an example.
client_name: Some(Localized::new("matrix-rust-sdk-oauth-cli".to_owned(), [])),
policy_uri: Some(client_uri.clone()),
tos_uri: Some(client_uri.clone()),
..ClientMetadata::new(