This site runs best with JavaScript enabled.

POC Use KeyCloak JWT to Authorize Hasura Queries

Photo by Zan on Unsplash


Proof-of-concept to use a JWT generated by KeyCloak to authorize queries in Hasura.

Building upon my last proof-of-concept, I now wanted to use my JWT from KeyCload to authenticate with Hasura.

Thankfully, this went pretty smoothly. I already had a user table configured in Hasura that I migrated from my last project. It is set up to allow a user to only query his/her user record.

screenshot of user permission in hasura

After logging in with KeyCloak, I ran a simple query to get all users to ensure it only returned the logged-in user.

1function getProfile(jwt) {
2 const gql = `
3 query MyQuery {
4 users {
5 id
6 email
7 first_name
8 last_name
9 last_seen
10 name
11 }
12 }
13 `
14 fetch('http://localhost:8080/v1/graphql', {
15 method: 'POST',
16 body: JSON.stringify({
17 query: gql,
18 }),
19 headers: {
20 'content-type': 'application/json',
21 Authorization: `Bearer ${jwt}`,
22 },
23 }).then(async data => {
24 // Console log our return data
25 user_data = await data.json()
26 if (user_data.data.users.length) {
27 document.getElementById('user-data').innerHTML = JSON.stringify(
28 user_data,
29 null,
30 2,
31 )
32 } else {
33 createProfile(jwt)
34 }
35 })
36}

Next, I wanted to register a new user and have it create a user record in Hasura. To make this work, I had to set up KeyCloak to give all newly registered users the user role by default. I did this by going to Roles -> default-roles-{realm} -> select hasura client -> add user to the Client Default Roles.

screen shot of default user role

Now when a user registers, their JWT will have the user role needed to make queries.

But, I need to create their profile if it does not exist. So I wrote a query to add a new user profile if one is not found after registering. It looks like this.

1function createProfile(jwt) {
2 const gql = `
3 mutation AddUser($auth_id: String!, $email: String!, $given_name: String, $family_name: String, $name: String) {
4 insert_users_one(object: {auth_id: $auth_id, email: $email, first_name: $given_name, last_name: $family_name, name: $name}) {
5 id
6 }
7 }
8 `
9 const decodedJwt = parseJwt(jwt)
10 fetch('http://localhost:8080/v1/graphql', {
11 method: 'POST',
12 body: JSON.stringify({
13 query: gql,
14 variables: {
15 auth_id: decodedJwt.sub,
16 email: decodedJwt.email,
17 given_name: decodedJwt.given_name,
18 family_name: decodedJwt.family_name,
19 name: decodedJwt.name,
20 },
21 }),
22 headers: {
23 'content-type': 'application/json',
24 Authorization: `Bearer ${jwt}`,
25 },
26 }).then(async data => {
27 // Console log our return data
28 const resp = await data.json()
29 console.log(resp)
30 getProfile(jwt)
31 })
32}

And here is another gif of the POC workflow:

demo gif

Discuss on TwitterEdit post on GitHub

Share article
Dustin Davis

Dustin Davis is a software engineer, people manager, hacker, and entreprenuer. He loves to develop systems and automation. He lives with his wife and five kids in Utah.

Join the Newsletter



Dustin Davis