Home

Awesome

Hasura JWT Auth

This project allows you to authenticate users from within Hasura and PostgreSQL. User data is stored in the hasura_user table that encrypts cleartext passwords using a trigger. The hasura_auth function can be made available for anonymous users to authenticate. After a successful authentication the Authorization: Bearer {jwt_token} header can be used in subsequent GraphQL calls.

The admin can create new users in the console or using GraphQL mutations on the hasura_user table.

Quickstart

The Docker quickstart initializes containers for PostgreSQL, Hasura and PgAdmin with an initial configuration for users/todos. Thanks go out to @dvasdekis.

Configuration

Hasura should be configured with a secret for the admin user and for signing the jwt tokens. You can use the following snippet to generate random secrets on the command line:

python3 -c 'import secrets; print(secrets.token_urlsafe(48))'

Set these configuration options when starting the Hasura engine and replace the secrets with your own values:

HASURA_GRAPHQL_UNAUTHORIZED_ROLE=anonymous
HASURA_GRAPHQL_ADMIN_SECRET=adminsecret
HASURA_GRAPHQL_JWT_SECRET='{"type":"HS256","key":"jwtsecret of 32 characters or more"}'

The SQL function needs to know the secret to generate jwt tokens so we store it as a setting in the database:

create database example;
\connect example
create extension if not exists pgcrypto;
alter database example set "hasura.jwt_secret_key" to 'jwtsecret of 32 characters or more';

Setup

Install the pgjwt extension or execute the pgjwt.sql script. This extension contains a sign function that does the the actual jwt signing.

Execute the hasura-jwt-auth.sql script and add tracking on the hasura_user table and the hasura_auth function. An easy way to do this is by navigating to the Data tab in Hasura and use the Raw SQL form. However this doesn't display the example jwt token as output.

Its also possible to use the psql client to load the script. Make sure that you connect using the same user as Hasura, or add a set role and \connect line in the script.

Table: hasura_user

<img src="images/hasura_user.png" alt="Hasura User" width="65%">

The table hasura_user table contains fields for:

Authentication

Set the permissions so that users with role anonymous are allowed to select the hasura_user table and allow only the jwt_token column.

<img src="images/anonymous-permissions.png" alt="Anonymous Permissions" width="100%">

Example authentication request:

query {
  hasura_auth(args: {email: "user@example.com", cleartext_password: "password"}) {
    jwt_token
  }
}

Use the returned jwt_token as a header:

<img src="images/authorization-header.png" alt="Authorization Header" width="100%">

Change password

The permissions of the user table can be configured so that an authenticated user is able to update its own email/password.

<img src="images/change-password.png" alt="Change password permissions." width="100%">

The password can be updated by setting the cleartext_password column which triggers setting the crypt_password to prevent storing cleartext passwords in the database. Warning: be careful with the configuration of log settings because its possible enable logging the input values of queries.

mutation {
  update_hasura_user(_set: {cleartext_password: "changed_password"}, where: {}) {
    returning {
      email
    }
  }
}

Troubleshooting

Use the jwt.io website to debug the contents of the generated jwt tokens check validation. You can emulate an anonymous user session in the console by setting the x-hasura-role: anonymous header.

Limitations

References

Contributors