dsferruzza / actix-web-middleware-keycloak-auth

A middleware for Actix Web that handles authentication with a JWT emitted by Keycloak
MIT License
30 stars 11 forks source link

Error while decoding JWT token (InvalidSignature) #13

Open slutske22 opened 10 months ago

slutske22 commented 10 months ago

This is perhaps more of a question than an issue with this crate, but forgive me I am not well versed in rust or backend OAuth.

When accessing a protected endpoint, I am getting the error:

Error while decoding JWT token (InvalidSignature)

Steps to reproduce:

Set up keycloak, with a custom realm. In the custom realm, there is an admin user, who has several custom roles associated with it.

In code, follow your example, but get the public key dynamically:

  // within fn main():

  // Get the 
   let keycloak_realm = reqwest::get("http://localhost:9220/realms/custom_realm")
        .await?
        .json::<KeycloakRealm>()
        .await;

    match keycloak_realm {
        Ok(realm) => {

            // realm.public_key is `MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1GFEiRT0DRkUmOg/HfjJRpEqgcAI3JY4krdSMF7+I1Qo0mKXBpRow3QkIEKqc4mPX3NEb2xVXVMkmHk+6+ykqg5cqyV4S2w+e9lQy2nQSqklp3u5Jlu7YsiTe26Xxmqn761H4O3VvdnufDt4Nhvl/yqc45EeyIC+WWDaKk68eG+/KqEumme3oAbddFtt9oAIdL2EGJJinO7GcckcVawuG0tN9Di5v6hoV8U0g9Mdjf3ZBXnS6vNG5nCacOTaNCdGHEkV97yzbB60Gh0YAv4cwGCZrMDzCAfMfBA5kWwTaChL5i4hO55YXPG4QveYq55xz2BMhdNUpyws7e0w2m0VCwIDAQAB`
           // confirmed this as RSA-OAEP in the keycloak UI

            let formatted = format!(
                "-----BEGIN RSA PUBLIC KEY-----\n{}\n-----END RSA PUBLIC KEY-----",
                &realm.public_key
            );

            let keycloak_auth = KeycloakAuth::default_with_pk(
                DecodingKey::from_rsa_pem(formatted.as_bytes()).unwrap(),
            );

            HttpServer::new(move || {
                let cors = Cors::default();

                let mut app = App::new()
                    .app_data(app_state.clone())
                    .app_data(reload_handle.clone())
                    .app_data(websocket_server.clone())
                    .app_data(tracker.clone())
                    .wrap(cors)

                app = app
                    .service(
                        web::scope("/v1/private")
                            // not sure why I have to clone this, if I don't, I get the error:
                            // cannot move out of `keycloak_auth`, a captured variable in an `Fn` closure
                            .wrap(keycloak_auth.clone())
                            .route(
                                "",
                                web::get().to(|| async { HttpResponse::Ok().body("Private") }),
                            ),
                    )

                app
            })
            .bind((BIND_ADDRESS, BIND_PORT))?
            .run()
            .await?;
        }
        Err(error) => {
            // Handle error stuff
        }
    }

All of this works, and the server is running. If I call the /private route with no token, I correctly get a 401 no auth error.

When I call the api to get the user, I get the token. Token looks something like:

eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ1QUlqZTNBUzM0d25Bblk4YmVGM1Z0Ulo1TWlJdzQycFB6c1FfV3lEVUNFIn0.eyJleHAiOjE3MDI5MTczNzIsImlhdCI6MTcwMjkxNzA3MiwiYXV0aF90aW1lIjoxNzAyOTE2NTkwLCJqdGkiOiI2MGM1ZGQ5MC03MmVkLTQyNjYtYWRiZi03Yjc5NzFjMjM5NjQiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkyMjAvcmVhbG1zL3N0YXRoZXJvcyIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiI2NjBmM2IyMy1hMjBhLTRhNzctYjUxYy1hMGU4YzRjNjcyMTAiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJyYXBjb24iLCJzZXNzaW9uX3N0YXRlIjoiZWM3MGY1MGYtNjZhMi00Njk4LTg2Y2YtYmJkMzA1NTAxODlmIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLXN0YXRoZXJvcyIsIlJPTEVfUkFQQ09OX0FETUlOIiwib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoib3BlbmlkIGVtYWlsIHByb2ZpbGUiLCJzaWQiOiJlYzcwZjUwZi02NmEyLTQ2OTgtODZjZi1iYmQzMDU1MDE4OWYiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluIn0.m0BpSB-ZZtnHP9H07AquMQMDSxKwE5vKCECdcb9FM98sxvSB_XXt59mcYL-gq9OKVYiBFPZrxlUdqssEPS_gNCdbPj-Drd93xLH59i07olz5Sin1p9hyya6JwptdBdL1pRNhGX9atwbyEmxi6W0WNcM2oqsM9mDY5HkGJDec9mF7n22uI2vnlvWY1E845CHVM8TWIeOlsMpKtnoY6qV0hS12alm_X6GKs1Cug1cMRCURQ_LDjKkUVn1HObgHV2vLcDk4PhyiB7nY-JZZJBNwB5Kcp2mXXqxjfADMZ5GekAoqdhMmEcCd8QwbRIfHCLD5g3bYNMOTR4VrFzBZGSpIVg

If you pop that into https://jwt.io/, it shows as signature verified for RS256.

In postman, I make a request to /v1/private with header Authorization: Bearer <token>, I get the error Error while decoding JWT token (InvalidSignature). I took at look at the other issue: https://github.com/dsferruzza/actix-web-middleware-keycloak-auth/issues/2, but it seems the problem there was already solved. I dug around stack overflow a bit as well for this issue, but since my JWT seems valid, I'm not sure what the issue might be.

This is probably not a bug with this crate? But what am I doing wrong in my setup? Am I passing the public key incorrectly? Am I making some wrong assumptions somewhere here?

dsferruzza commented 10 months ago

Hi!

Your approach seems fine 🤔 Just in case, could you try with this?

let formatted = format!(
    "-----BEGIN PUBLIC KEY-----{}-----END PUBLIC KEY-----",
    &realm.public_key
);
slutske22 commented 10 months ago

@dsferruzza So I tried that, and various variations of formatting the key, unfortunately no change.

Any other brainstorming idea on how to debug my setup? Thank you so much!

dsferruzza commented 10 months ago

Could you try to get more info/context by:

  1. Adding env_logger to your project
  2. Calling its init function at the beginning of main
  3. Running you app with the RUST_LOG="trace" environment variable
  4. Sending the request that fails to your app
  5. Putting the logs here

?

ArbazIrshad commented 3 weeks ago

Hello @slutske22, were you able to fix this issue? I am facing the same issue but with axum. Although, I am creating a custom access token and making an http request from a keycloak SPI.

slutske22 commented 2 weeks ago

@ArbazIrshad I didn't....but this was for a personal project with little consequence, so I sorta gave up. LMK if you find a solution!

ArbazIrshad commented 2 weeks ago

I will report back to you if I find a fix. Thanks for taking the time to reply.

ArbazIrshad commented 2 weeks ago

hey @slutske22, It looks like I needed to set everything up in keycloak before starting my axum server.