Giter Site home page Giter Site logo

hasura-jwt-auth's Introduction

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: "[email protected]", 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

hasura-jwt-auth's People

Contributors

dvasdekis avatar sanderhahn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

hasura-jwt-auth's Issues

Token refresh/renewal

Have you considered how token refresh/renewal might work using this setup?

As long as the user is actively using the system it would be ideal if they could continue to do so without having to re-auth.

Just looking for ideas if you've got them.

BTW, I have this setup running in a limited release production environment!

UUID?

I'm trying to add the hasura_auth function to an existing hasura instance and using my own users table. When I try to run the sql I get and error:

Final statement returns text instead of uuid at column 5.

Any ideas? Here's the sql I'm using.

create or replace function hasura_auth(email in varchar, cleartext_password in varchar) returns setof users as $$
    select
        uuid::uuid,
        email,
        password_hash,
        cleartext_password,
        default_role,
        allowed_roles,
        enabled,
        sign(
            json_build_object(
                'sub', uuid::text,
                'iss', 'Hasura-JWT-Auth',
                'iat', round(extract(epoch from now())),
                'exp', round(extract(epoch from now() + interval '24 hour')),
                'https://hasura.io/jwt/claims', json_build_object(
                    'x-hasura-user-id', uuid::text,
                    'x-hasura-default-role', default_role,
                    'x-hasura-allowed-roles', allowed_roles
                )
            ), current_setting('hasura.jwt_secret_key')) as jwt_token
    from users u
    where u.email = hasura_auth.email
    and u.enabled
    and u.password_hash = hasura_encrypt_password(hasura_auth.cleartext_password, u.password_hash);
$$ language 'sql' stable;

Can't get the JWT again for the user with a different DB connection

Hi Sander, I am following your scripts and the database generates and displays a JWT when it first initializes via below section of code:

insert into hasura_user(email, cleartext_password) values ('[email protected]', 'password');

do $$ begin
    raise notice 'Example jwt_token: %s', (select jwt_token from hasura_auth('[email protected]', 'password'));
end $$;

The above returns the result of NOTICE: Example jwt_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiIDogIjEiLCAiaXNzIiA6ICJIYXN1cmEtSldULUF1dGgiLCAiaWF0IiA6IDE1NjM5NTE4MjUsICJleHAiIDogMTU2NDAzODIyNSwgImh0dHBzOi8vaGFzdXJhLmlvL2p3dC9jbGFpbXMiIDogeyJ4LWhhc3VyYS11c2VyLWlkIiA6ICIxIiwgIngtaGFzdXJhLWRlZmF1bHQtcm9sZSIgOiAidXNlciIsICJ4LWhhc3VyYS1hbGxvd2VkLXJvbGVzIiA6IFsidXNlciJdfX0.T87RNdXKP3QQhgl6i-QQy8FIp5ecsQxEdH2M8He7tdAs which is as expected.

However, if I then create a different connection to the database and run the below, I am unable to get the JWT again:

do $$ begin
    raise notice 'Example jwt_token: %s', (select jwt_token from hasura_auth('[email protected]', 'password'));

The above returns the result of NOTICE: Example jwt_token: <NULL>s which is problematic. Hasura will potentially use a different connection to the database for user creation VS token generation.

Cannot verify Signature

Hey, I think this whole concept is amazing.
Im currently facing this problem, not being able to verify signature.
When I try signature in jwt.io with it does validate.
Screen Shot 2020-02-27 at 12 06 50 AM

Volatile functions for signup and change_password?

This is an awesome approach. I love it and wish it were part of Hasura main.

When VOLATILE stored procedures are available (soon I hope) will you add support for signup and change_password functions?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.