Add basic demo SPA to display claims
This commit is contained in:
parent
15763cd0bb
commit
0f110d70b4
@ -1,2 +1,3 @@
|
||||
.github
|
||||
example
|
||||
target
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,3 +1,5 @@
|
||||
/target
|
||||
**/target
|
||||
/static/build
|
||||
wrangler.toml
|
||||
**/wrangler.toml
|
||||
**/node_module
|
||||
**/dist
|
||||
|
3
example/demo/.env
Normal file
3
example/demo/.env
Normal file
@ -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"
|
17
example/demo/Cargo.toml
Normal file
17
example/demo/Cargo.toml
Normal file
@ -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"] }
|
30
example/demo/README.md
Normal file
30
example/demo/README.md
Normal file
@ -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
|
||||
```
|
10
example/demo/index.html
Normal file
10
example/demo/index.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
122
example/demo/src/main.rs
Normal file
122
example/demo/src/main.rs
Normal file
@ -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! {
|
||||
<>
|
||||
<form action="https://oidc.login.xyz/authorize">
|
||||
<input type="hidden" name="client_id" value={ CLIENT_ID.clone() } />
|
||||
<input type="hidden" name="response_type" value="code" />
|
||||
<input type="hidden" name="nonce" value="nonce" />
|
||||
<input type="hidden" name="scope" value="openid profile" />
|
||||
<input type="hidden" name="state" value="state" />
|
||||
<input type="hidden" name="redirect_uri" value={ REDIRECT_URI.to_string() } />
|
||||
<input type="submit" value="Sign-In with Ethereum using OpenID Connect" />
|
||||
</form>
|
||||
</>
|
||||
}
|
||||
}
|
||||
|
||||
#[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! {
|
||||
<>
|
||||
<p>{ (*claims).clone() }</p>
|
||||
</>
|
||||
}
|
||||
}
|
||||
|
||||
fn switch(routes: &Route) -> Html {
|
||||
match routes {
|
||||
Route::Home => html! { <SIWE /> },
|
||||
Route::OIDCCallback => html! { <Callback /> },
|
||||
Route::NotFound => html! { <Redirect<Route> to={Route::Home}/> },
|
||||
}
|
||||
}
|
||||
|
||||
#[function_component(App)]
|
||||
fn app() -> Html {
|
||||
html! {
|
||||
<BrowserRouter>
|
||||
<Switch<Route> render={Switch::render(switch)} />
|
||||
</BrowserRouter>
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
yew::start_app::<App>();
|
||||
}
|
3
example/demo/workers-site/.gitignore
vendored
Normal file
3
example/demo/workers-site/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
dist
|
||||
worker
|
39
example/demo/workers-site/index.js
Normal file
39
example/demo/workers-site/index.js
Normal file
@ -0,0 +1,39 @@
|
||||
import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler'
|
||||
|
||||
const DEBUG = false
|
||||
|
||||
addEventListener('fetch', event => {
|
||||
event.respondWith(handleEvent(event))
|
||||
})
|
||||
|
||||
async function handleEvent(event) {
|
||||
let options = {}
|
||||
options.mapRequestToAsset = spaRouting()
|
||||
options.cacheControl = {
|
||||
bypassCache: DEBUG,
|
||||
}
|
||||
|
||||
try {
|
||||
const page = await getAssetFromKV(event, options)
|
||||
const response = new Response(page.body, page)
|
||||
response.headers.set('X-XSS-Protection', '1; mode=block')
|
||||
response.headers.set('X-Content-Type-Options', 'nosniff')
|
||||
response.headers.set('X-Frame-Options', 'DENY')
|
||||
response.headers.set('Referrer-Policy', 'unsafe-url')
|
||||
response.headers.set('Feature-Policy', 'none')
|
||||
return response
|
||||
} catch (e) {
|
||||
return new Response(e.message || e.toString(), { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
function spaRouting() {
|
||||
return request => {
|
||||
let defaultAssetKey = mapRequestToAsset(request)
|
||||
let url = new URL(defaultAssetKey.url)
|
||||
if (url.pathname.includes(".html")) {
|
||||
url.pathname = "/index.html"
|
||||
}
|
||||
return new Request(url.toString(), defaultAssetKey)
|
||||
}
|
||||
}
|
10
example/demo/workers-site/package.json
Normal file
10
example/demo/workers-site/package.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"description": "A template for kick starting a Cloudflare Workers project",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@cloudflare/kv-asset-handler": "~0.1.2"
|
||||
}
|
||||
}
|
19
example/demo/wrangler_example.toml
Normal file
19
example/demo/wrangler_example.toml
Normal file
@ -0,0 +1,19 @@
|
||||
name = "siwe-oidc-demo"
|
||||
type = "webpack"
|
||||
account_id = ""
|
||||
|
||||
workers_dev = false
|
||||
|
||||
zone_id = ""
|
||||
routes = ["demo-oidc.login.xyz/*"]
|
||||
|
||||
compatibility_date = "2022-02-10"
|
||||
|
||||
[build]
|
||||
command = "cargo install -q trunk && trunk build"
|
||||
|
||||
[build.upload]
|
||||
format = "service-worker"
|
||||
|
||||
[site]
|
||||
bucket = "./dist"
|
Loading…
Reference in New Issue
Block a user