Skip to content

Instantly share code, notes, and snippets.

@webdeb
Last active October 29, 2022 19:03
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save webdeb/d8a99df9023f01b78e3e8ff580abe10b to your computer and use it in GitHub Desktop.
Save webdeb/d8a99df9023f01b78e3e8ff580abe10b to your computer and use it in GitHub Desktop.
Basic Keycloak Script Mapper to provide Hasura claims

Steps to provide Hasura Claims in Keycloak generated JWT

  1. Create your realm / client
  2. Inside client configuration go to "Mappers"
  3. Click on "Create"
  4. Name it "hasura"
  5. Choose Mapper Type "Script Mapper"
  6. Add following script to demonstrate how it works
/**
 * Available variables: 
 * user - the current user (UserModel)
 * realm - the current realm (RealmModel)
 * token - the current token (TokenModel)
 * userSession - the current userSession (UserSessionModel)
 * keycloakSession - the current keycloakSession (KeycloakSessionModel)
 */


//insert your code here...
var roles = [];
for each (var role in user.getRoleMappings()) roles.push(role.getName());
token.setOtherClaims("https://hasura.io/jwt/claims", {
    "x-hasura-user-id": user.getId(),
    "x-hasura-allowed-roles": Java.to(roles, "java.lang.String[]"),
    "x-hasura-default-role": "user",
});

Thats it, the next step is just to verify your settings

  1. Go to clients -> your-client -> Scopes -> Evaluate
  2. Select an user, and see the generated JWT payload in "Generated Access Token" Tab

Update: Keycloak has a new policy. they disable ScriptMappers by default You have to start the instance with this flag:

-Dkeycloak.profile.feature.upload_scripts=enabled

@webdeb
Copy link
Author

webdeb commented Dec 27, 2019

Update, since keycloak 7.0.1 Script Mapping is disabled by default, how to deploy scripts/enable read here:
https://www.keycloak.org/docs/latest/server_development/#_script_providers

@eduardosanzbBCG
Copy link

THANK YOU!

@raarts
Copy link

raarts commented Jun 5, 2020

@eduardosanzbBCG were you able to get this to work? Following that manual I created a deploy script jar file, Keycloak recognized it and deployed it, but I can't find it anywhere in the GUI.

@eduardosanzbBCG
Copy link

eduardosanzbBCG commented Jun 6, 2020

Yes, but using docker image


keycloak:
--
  | image: quay.io/keycloak/keycloak:latest
  | command:
  | - "-Dkeycloak.profile.feature.upload_scripts=enabled"
  | environment:
  | DB_VENDOR: POSTGRES
  | DB_ADDR: postgres
  | DB_DATABASE: keycloak
  | DB_USER: keycloak
  | DB_SCHEMA: public
  | DB_PASSWORD: password
  | KEYCLOAK_USER: admin
  | KEYCLOAK_PASSWORD: Pa55w0rd
  | # Uncomment the line below if you want to specify JDBC parameters. The parameter below is just an example, and it shouldn't be used in production without knowledge. It is highly recommended that you read the PostgreSQL JDBC driver documentation in order to use it.
  | #JDBC_PARAMS: "ssl=true"
  | ports:
  | - 8080:8080
  | depends_on:
  | - postgres

@webdeb
Copy link
Author

webdeb commented Jun 6, 2020

@raarts when you deploy the script you can find it here:
Bildschirmfoto 2020-06-06 um 12 41 13

@raarts
Copy link

raarts commented Jun 7, 2020

Yes: this exactly was the reason, I did not add that flag:

"-Dkeycloak.profile.feature.upload_scripts=enabled"

@JesseVelden
Copy link

JesseVelden commented Aug 12, 2020

So as I find the Keycloak documentation a bit confusing, if you go the JAR way you can have this in your META-INF/keycloak-scripts.json:

{
    "authenticators": [],
    "policies": [],
    "mappers": [
        {
            "name": "Hasura Mapper",
            "fileName": "hasura-mapper.js",
            "description": "Hasura Mapper from a JS file"
        }
    ]
}

and put in ./hasura-mapper.js the script from OP. Zip that folder and change the extension to a .jar, and if you use a docker-compose configuration, you can do it like this:

 keycloak:
    image: quay.io/keycloak/keycloak:latest
    command: -Dkeycloak.profile.feature.upload_scripts=enabled
    ...
    volumes:
      - type: bind
        source: ./hasura-keycloak.jar
        target: /opt/jboss/keycloak/standalone/deployments/hasura-keycloak.jar

I think -Dkeycloak.profile.feature.upload_scripts=enabled is still needed because of a bug, that they just didn't update yet.

Next you can add HASURA_GRAPHQL_JWT_SECRET: '{"jwk_url":"https://keycloakhost/auth/realms/xxRealmNamexx/protocol/openid-connect/certs"}' to your Hasura docker-compose.yaml as an environment variable.

@jaekook-neonesia
Copy link

jaekook-neonesia commented Aug 14, 2020

Another Approach..

  • Goto Mapper Menu
  • Create Below 3 Mapper
    =================================================
    Protocol: openid-connect
    Name: hasura-claim-user-id
    Mapper Type: User Property
    Property: id
    Token Claim Name: https://hasura\.io/jwt/claims.x-hasura-user-id
    =================================================
    Protocol: openid-connect
    Name: hasura-claim-default-role
    Mapper Type: Hardcoded claim
    Token Claim Name: https://hasura\.io/jwt/claims.x-hasura-default-role
    Claim value: [Your Single Client Role]
    =================================================
    Protocol: openid-connect
    Name: hasura-claim-allowed-roles
    Client ID: [Your Hasura Client ID]
    Mapper Type: User Client Role
    Multivalued: On
    Token Claim Name: https://hasura\.io/jwt/claims.x-hasura-allowed-roles
    =================================================

@webdeb
Copy link
Author

webdeb commented Aug 16, 2020

@MegaCookie you are right. The initial gist was for keycloak 7 or so, and they have disabled scriptmappers in newer versions, you have to enable it manually -Dkeycloak.profile.feature.upload_scripts=enabled

@webdeb
Copy link
Author

webdeb commented Aug 16, 2020

@jaekook-neonesia actually a very good and simple approach, thank you for sharing this

@msalehy
Copy link

msalehy commented Dec 29, 2020

@jaekook-neonesia very practical method. its working perfectly

@ClementVanPeuter
Copy link

Wonderfull ;) Now how can we sync our Keycloak users with Hasura.
In auth0 we can add a mutation script to replicate our users when they login/register in hasura.

How can we achieve this with keycloak ?

@webdeb
Copy link
Author

webdeb commented Jan 25, 2021

@ClementVanPeuter keycloak is open source so there are a lot of plugins, if you look for some sort of webhooks / events stuff. I haven't used any myself, just know that it should be possible.

@webdeb
Copy link
Author

webdeb commented Jan 25, 2021

Now how can we sync our Keycloak users with Hasura.

I would't at all. Just let the user sign-in and use your app, load the user by id, if not found, create the new user.

@lukwil
Copy link

lukwil commented Feb 28, 2021

If someone wants to use composite roles (as I did) and wonders how to do so, here is my working script:

var roles = [];
for each (var role in user.getRoleMappings()) {
    if (role.isComposite()) {
        var composites = role.getComposites();
        var compositeRoleNames = [];
        for each (var composite in composites) {
            compositeRoleNames.push(composite.getName());
        }
        // push all composite role names to roles (equal to modern JS ...compositeNames)
        Array.prototype.push.apply(roles, compositeRoleNames);
    }
    // include role itself, not just possible composites
    roles.push(role.getName());
};

token.setOtherClaims("https://hasura.io/jwt/claims", {
    "x-hasura-user-id": user.getId(),
    "x-hasura-allowed-roles": Java.to(roles, "java.lang.String[]"),
    "x-hasura-default-role": "user",
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment