POC Use KeyCloak JWT to Authorize Hasura Queries
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.
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 id6 email7 first_name8 last_name9 last_seen10 name11 }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 data25 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.
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 id6 }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 data28 const resp = await data.json()29 console.log(resp)30 getProfile(jwt)31 })32}
And here is another gif of the POC workflow: