diff --git a/.dockerignore b/.dockerignore index f2c136e..8a3a6c4 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,3 @@ .github example +target diff --git a/.gitignore b/.gitignore index 2517629..ff6ab22 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ -/target +**/target /static/build -wrangler.toml +**/wrangler.toml +**/node_module +**/dist diff --git a/example/demo/.env b/example/demo/.env new file mode 100644 index 0000000..94c1917 --- /dev/null +++ b/example/demo/.env @@ -0,0 +1,3 @@ +CLIENT_ID="8f169184-8815-457c-a32f-85b39fbcfca7" +CLIENT_SECRET="430d8ade-d2d7-48c1-9c68-b97fcd73967d" +REDIRECT_URI="https://demo-oidc.login.xyz/callback" diff --git a/example/demo/Cargo.toml b/example/demo/Cargo.toml new file mode 100644 index 0000000..e9bfb14 --- /dev/null +++ b/example/demo/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "demo" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +yew = "0.19.3" +yew-router = "0.16.0" +url = "2.2.2" +lazy_static = "1.4.0" +serde = "1.0.136" +openidconnect = {git = "https://github.com/sbihel/openidconnect-rs", branch = "main", default-features = false, features = ["reqwest", "rustls-tls", "rustcrypto"]} +wasm-bindgen-futures = "0.4.29" +serde_json = "1.0.78" +chrono = { version = "0.4.19", features = ["wasmbind"] } diff --git a/example/demo/README.md b/example/demo/README.md new file mode 100644 index 0000000..8145c00 --- /dev/null +++ b/example/demo/README.md @@ -0,0 +1,30 @@ +# Demo Single Page Application for the OIDC IdP + +This demo's purpose is to display the claims that are shared with Relying +Parties. It is currently deployed at https://demo-oidc.login.xyz. + +## Dependencies + +```sh +$ cargo install trunk +$ rustup target add wasm32-unknown-unknown +``` + +## Development + +```sh +trunk serve --open +``` + +## Deploy + +```sh +cp wrangler_example.toml wrangler.toml +``` +And fill in `account_id` and `zone_id`. + +```sh +$ source .env +$ trunk build +$ wrangler publish +``` diff --git a/example/demo/index.html b/example/demo/index.html new file mode 100644 index 0000000..e634ace --- /dev/null +++ b/example/demo/index.html @@ -0,0 +1,10 @@ + + +
+ + + + + + + diff --git a/example/demo/src/main.rs b/example/demo/src/main.rs new file mode 100644 index 0000000..60e5815 --- /dev/null +++ b/example/demo/src/main.rs @@ -0,0 +1,122 @@ +use openidconnect::{ + core::{CoreAuthenticationFlow, CoreClient, CoreProviderMetadata}, + reqwest::async_http_client, + AuthorizationCode, ClientId, ClientSecret, CsrfToken, IssuerUrl, Nonce, Scope, TokenResponse, +}; +use serde::Deserialize; +use url::Url; +use wasm_bindgen_futures::spawn_local; +use yew::prelude::*; +use yew_router::{hooks::use_location, prelude::*}; + +lazy_static::lazy_static! { +static ref CLIENT_ID: String = option_env!("CLIENT_ID").unwrap_or("fb24a7d9-6db9-476b-93c4-e8562e750250").to_string(); +static ref CLIENT_SECRET: String = option_env!("CLIENT_SECRET").unwrap_or("6aae6334-148f-464c-a4bf-a204e62e197c").to_string(); +static ref REDIRECT_URI: Url = Url::parse(option_env!("REDIRECT_URI").unwrap_or("http://localhost:8080/callback")).unwrap(); +} + +#[derive(Clone, Routable, PartialEq)] +enum Route { + #[at("/")] + Home, + #[at("/callback")] + OIDCCallback, + #[not_found] + #[at("/404")] + NotFound, +} + +#[function_component(SIWE)] +pub fn siwe() -> Html { + html! { + <> + + > + } +} + +#[derive(Deserialize)] +struct CallbackParams { + code: String, + _state: String, +} + +#[function_component(Callback)] +pub fn callback() -> Html { + let location = use_location().unwrap(); + let params: CallbackParams = location.query().unwrap(); + + let claims = use_state(String::default); + let claims2 = claims.clone(); + spawn_local(async move { + let provider_metadata = CoreProviderMetadata::discover_async( + IssuerUrl::new("https://oidc.login.xyz/".to_string()).unwrap(), + async_http_client, + ) + .await + .unwrap(); + let client = CoreClient::from_provider_metadata( + provider_metadata, + ClientId::new(CLIENT_ID.to_string()), + Some(ClientSecret::new(CLIENT_SECRET.to_string())), + ); + let (_auth_url, _csrf_token, nonce) = client + .authorize_url( + CoreAuthenticationFlow::AuthorizationCode, + CsrfToken::new_random, + || Nonce::new("nonce".to_string()), + ) + .add_scope(Scope::new("openid".to_string())) + .add_scope(Scope::new("profile".to_string())) + .url(); + let token_response = client + .exchange_code(AuthorizationCode::new(params.code)) + .request_async(async_http_client) + .await + .unwrap(); + let id_token = token_response.id_token().unwrap(); + claims2.set( + serde_json::to_string( + id_token + .claims(&client.id_token_verifier(), &nonce) + .unwrap(), + ) + .unwrap(), + ); + }); + + html! { + <> +{ (*claims).clone() }
+ > + } +} + +fn switch(routes: &Route) -> Html { + match routes { + Route::Home => html! {