Extract custom claims from JWT (retrieved by keycloak) using rust openid

I'm using rust openid to authenticate against a Keycloak instance.
I would like to use client roles that should be represented in the access token.
The roles are mapped correctly, and the access token generated by Keycloak contains the roles.

So far I have been unable to extract those roles from the token.
Neither the default claims nor UserInfo can be used to extract such additional roles information or other custom claims.

A decrypted access token might look like this:

{
  ...
  "resource_access": {
    "some-client": {
      "roles": [
        "view",
        "edit",
        "delete"
      ]
    },
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }
  },
  "scope": "openid email profile",
  "email_verified": true,
  "custom-claim": [
    "this",
    "is",
    "custom"
  ],
  "name": "Test Tester",
  ...
}

Of course I could decrypt the RSA access token manually and extract the information, although I'm not 100% sure on how to do this, but I'm pretty sure there has to be an easier way than this, right?

Can anybody help me with this problem?

I think Keycloak is providing roles only when your request contains roles as part of your scopes. Try to use something like "openid email profile roles" as scope.

I might be very wrong but IIRC there are options in Keycloak to provide some scopes in Identity tokens, in that case they won't be provided in access tokens.

Do you have an example in other language which works? It might be that the Keycloak needs configuring in which case the question might be more suitable for the Keycloak chat.

I have no idea about keycloak but I have been juggling JWTs with the 'jwt' crate.
Which can extract all claims from a JWT.

        let key: Hmac<Sha256> = Hmac::new_varkey(&self.key.into_bytes()).unwrap();

        let claims: BTreeMap<String, String> = match token.verify_with_key(&key) {
            Ok(o) => o,
            Err(e) => {
                error!("JWT verification failed: {}", e);
                let res =
                    tungstenite::handshake::server::ErrorResponse::new(Some("Go away".to_string()));
                return Err(res);
            }
        };
        info!("JWT verified:");
        info!("iss:  {}", claims.get("iss").unwrap());
        info!("sub:  {}", claims.get("sub").unwrap());
        info!("aud:  {}", claims.get("aud").unwrap());
        info!("exp:  {}", claims.get("exp").unwrap());
        info!("nbf:  {}", claims.get("nbf").unwrap());
        info!("iat:  {}", claims.get("iat").unwrap());
        info!("user: {}", claims.get("user").unwrap());
        info!("customClaim: {}", claims.get("customClaim").unwrap());

1 Like

Do you by chance have an RSA example too?

Sadly not. That is about the limit of my working with JWTs.

I'm sure what you want is possible, given the number of Rust JWT crates listed on the https://jwt.io/ page and all the boxed they have checked.

Interestingly the jwt create I am using is not listed there.

Looks like biscuit might do what you want, judging by the nice example code here:
https://docs.rs/biscuit/0.4.2/biscuit/type.JWT.html

Where SignatureAlgorithm canbe any of these:
https://docs.rs/biscuit/0.4.2/biscuit/jwa/enum.SignatureAlgorithm.html

I have no idea really, you just got me curious to see what is out there in JWT land.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.