Any examples of PKCE flow in Rust?

Most of the relevant code I have tried thus far

Code
Code verifier
fn code_verifier() -> String {
    use base64::prelude::{Engine, BASE64_URL_SAFE};
    let window = web_sys::window().unwrap();
    let crypto = window.crypto().unwrap();
    let mut rand_buffer = [0u8; 32];
    let rand_bytes = crypto.get_random_values_with_u8_array(&mut rand_buffer);
    assert!(rand_bytes.is_ok());
    BASE64_URL_SAFE.encode(rand_buffer)
}

fn code_verifier() -> String {
    use rand::distributions::Alphanumeric;
    use rand::{thread_rng, Rng};

    thread_rng()
        .sample_iter(&Alphanumeric)
        .take(32)
        .map(char::from)
        .collect()
}
B64 Encode
fn b64_encode(input: &str) -> String {
    use base64::prelude::BASE64_URL_SAFE_NO_PAD;

    BASE64_URL_SAFE_NO_PAD
        .encode(input)
        .replace('=', "")
        .replace('+', "-")
        .replace('/', "_")
}
Sha256

I had another using Sha256 but forgot to save it anywhere, I doubt it’s the culprit.

fn sha256(input: &str) -> String {
    use cryptoxide::digest::Digest;
    use cryptoxide::sha2::Sha256;

    let mut hasher = Sha256::new();
    hasher.input_str(input);
    hasher.result_str()
}
Requests

The application is built using Leptos with CSR, for context.

This works fine as far as I can tell, I get a code and the verifier is stored (not sure if this is particularly safe, but the application isn’t public yet so I can change it later) to be reused

#[component]
pub fn LoginPanel() -> impl IntoView {
    let code_verifier = code_verifier();
    let code_challenge = b64_encode(&sha256(&code_verifier));

    let url = url::Url::parse_with_params(
        "{domain}/authorize",
        vec![
            ("response_type", "code"),
            ("code_challenge", &code_challenge),
            ("code_challenge_method", "S256"),
            ("client_id", "{client_id}"),
            ("redirect_uri", "http://127.0.0.1:8081/auth"),
            ("scope", "openid profile email"),
            ("audience", "{audience}"),
        ],
    )
    .unwrap()
    .to_string();

    use_local_storage::<String, JsonCodec>("code_verifier")
        .1
        .set(code_verifier);

    view! {
        <div>
                <a href=url>
                    "Login"
                </a>
        </div>
    }
}

The next step is where things go awry, I get a 401 error with no details.

#[component]
fn Auth() -> impl IntoView {
    let code_verifier = use_local_storage::<String, JsonCodec>("code_verifier")
        .0
        .get_untracked();

    let code = web_sys::UrlSearchParams::new_with_str(
        &web_sys::window().unwrap().location().search().unwrap(),
    )
    .unwrap()
    .get("code")
    .unwrap();

    spawn_local(async move {
        let url = url::Url::parse_with_params(
            "{domain}/oauth/token",
            vec![
                ("grant_type", "authorization_code"),
                ("client_id", "{client_id}"),
                ("code_verifier", code_verifier.as_str()),
                ("code", code.as_str()),
                ("redirect_uri", "{redirect_uri}"),
            ],
        )
        .unwrap();

        let response = reqwasm::http::Request::post(url.as_str())
            .header("content-type", "application/x-www-form-urlencoded")
            .send()
            .await;

        log!("{:?}", response);
    });

    view! {
        <div>"Auth"</div>
    }
}

I’m following Call Your API Using the Authorization Code Flow with PKCE in Rust, but when trying to call oauth/token I get a 401 error with no real details and nothing in the logs for me to understand why it’s happening.

Has anyone done this themselves without the Auth0 package/library that is willing to share an example, or can explain what I’m doing wrong here?

Hi @ZizoAdam,

Welcome to the Auth0 Community and sorry for the late reply!

In order to use Rust within Auth0 i would recommend following up this documentation about Application Implementation (Server Apps + API) which explains that:

You need to implement a middleware function within your API application to handle tokens. This function checks if a token was included with the API request, validates the token, and then confirms if the scope(s) required to perform the requested action are present.

Otherwise a HTTP 401 Unauthorized status code will be presented.

There aren’t lots of up to date examples, but this blog post provides step by step instructions on how to set up an API in Rust with JWT Authentication using Nickel.rs, including a middleware function example.

Hope this helps.
Thanks,
Remus

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.