Skip to content

Latest commit

 

History

History
125 lines (86 loc) · 4.88 KB

readme.md

File metadata and controls

125 lines (86 loc) · 4.88 KB

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

Hasura User

The table hasura_user table contains fields for:

  • user_id - serial
  • email (unique) - used as username
  • crypt_password - contains an encrypted password
  • cleartext_password - is always cleared and only used for input
  • default_roke - the default role of the user
  • allowed_roles - jsonb array of allowed roles
  • enabled - boolean default true
  • jwt_token - is never set and only used for output

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.

Anonymous Permissions

Example authentication request:

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

Use the returned jwt_token as a header:

Authorization Header

Change password

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

Change password permissions.

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

  • No password strength is enforced.
  • Tokens are set to expire after 24 hours with the exp claim, however you can adjust the interval.
  • Existing tokens will not invalidate when a user is disabled, however no new tokens can be generated.
  • The jwt_secret is stored inside the database instead of a password vault.

References

Contributors