/

hasura-header-illustration

Hasura Authentication Explained

This post was published originally on Apr 2019 and has been edited (significantly) in May 2020

Handling authentication correctly is a key step in ensuring the security of your application in production. In this post we will look at the various options for authentication with Hasura.

Hasura supports 4 methods of authentication

  1. Admin secret based authentication: Use this method if you are doing server to server communication and the client is a trusted client.
  2. JSON web tokens (JWT) based authentication: Use this method if you are authenticating your end-users using a JWT based authentication provider like Auth0 or Firebase or AWS Cognito
  3. Webhook based authentication: Use this method if you need to roll out a custom authentication solution.
  4. Unauthenticated access: Use this method if you want to provide anonymous access to some data, for example if you want to make a public feed of events.

We will understand how each of these methods works below, but first we must understand the related topics of Authorization & Session Variables.

Authorization & Session Variables

While authentication deals with "Is this user valid?", Authorization deals with "Does this (valid) user have permission to access this resource or perform this action?". Hasura comes with a built-in role-based access control system. We have put together a post here explaining how this works:

Every  request to Hasura executes against a set of session variables. These  variables are expected to be set by the authentication system. While arbitrary variables can be set and used in defining authorization rules, two variables are of particular interest in the context of authorization:
X-Hasura-User-Id: This variable usually denotes the user executing the request.
X-Hasura-Role:  This variable denotes the role with which the user is executing the  current request. Hasura has a built-in notion of a role and will  explicitly look for this variable to infer the role.

Session variables are the link that ties authentication and authorization together. The exact mechanism of how these variables get set depends on the authentication mechanism.

This is the simplest mode of authentication. Here's how authentication with an admin secret works:

  1. Hasura is configured with an admin password on startup
  2. When making an API request the client passes the admin password in the header X-Hasura-Admin-Secret
  3. Hasura validates the admin secret and allows access to all resources

The secret is called admin-secret since the admin role is used to execute the request i.e the caller will have permissions to create/update/delete/view any data that is there. So use this method with caution!

This method of authentication also takes precedence over JWT and webhook based authentication i.e if X-Hasura-Admin-Secret is set correctly, Hasura will always execute the request with admin privileges.

Configuring Hasura with an admin password

When creating a new instance of Hasura engine, the first thing you want to do is to Secure your GraphQL endpoint:

To do this, we need to pass the environment variable HASURA_GRAPHQL_ADMIN_SECRET while starting Hasura. Hasura docs describe the instructions for doing this on Heroku, on Docker, and on Kubernetes.

Once the environment variable is set, if you try to access the console, you will get a simple "login" page that will ask you to specify your secret

You can also now use the admin-secret to make API requests by setting the X-Hasura-Admin-Secret:

curl 'https://<hasura-host>/v1/graphql' -H 'x-hasura-admin-secret: <admin-secret>'  --data-binary '<graphql-query>'

Session variables when using an admin secret

We do not need to worry about session variables with an admin secret, because session variables are used for writing authorization rules and admin secret always gives access to all resources.

In this post, we assume you are familiar with what a JWT is. If you are new to JWT's here is a guide we have put together explaining how JWT's work in the context of front end GraphQL clients. It also covers the security aspects of using a JWT for authentication.

Here's how JWT based authentication works:

  1. An end-user is authenticated on the app by your authentication server
  2. On successful authentication, the authentication server returns a JWT to the app with the user and role information embedded in the claims section
  3. The app passes the JWT in the Authorization header to Hasura
  4. Hasura validates the token and extracts the user and role information

Configuring Hasura for JWT validation

some data

Validating the JWT Token in step 4. above requires a JWT secret. You can enable JWT mode by using the --jwt-secret flag or HASURA_GRAPHQL_JWT_SECRET environment variable while starting Hasura. The the value of the flag or environment variable must be a JSON object:

{
  "type": "<optional-type-of-key>",
  "key": "<optional-key-as-string>",
  "jwk_url": "<optional-url-to-refresh-jwks>",
  "claims_namespace": "<optional-key-name-in-claims>",
  "claims_namespace_path":"<optional-json-path-to-the-claims>",
  "claims_format": "json|stringified_json",
  "audience": <optional-string-or-list-of-strings-to-verify-audience>,
  "issuer": "<optional-string-to-verify-issuer>"
}

The type, key, audience and issuer fields are used for validating the JWT whereas the claims_* fields are used for extracting session variables.

Session variables with JWT based Authentication

Hasura will look under https://hasura.io/jwt/claims namespace (or the namespace configured above) in the token, extract x-hasura-* prefixed variables and use them as session variables. For example for the below JWT...

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "iat": 1516239022,
  "https://hasura.io/jwt/claims": {
    "x-hasura-allowed-roles": ["editor","user", "mod"],
    "x-hasura-default-role": "user",
    "x-hasura-user-id": "1234567890",
    "x-hasura-org-id": "123",
    "x-hasura-custom": "custom-value"
  }
}

... Hasura will extract the session variables x-hasura-allowed-roles, x-hasura-default-role, x-hasura-user-id, x-hasura-org-id and x-hasura-custom. You can then write permission rules to use these session variables.

Integrating with JWT based authentication providers

Here are some resources on integrating JWT based Auth for some popular authentication providers:

Here is how webhook based auth works:

  1. The app calls a GraphQL API on Hasura passing on authentication credentials in headers. This can be a session token or an API key for something custom.
  2. Hasura calls a pre-configured webhook. Hasura will forward the headers to the API.
  3. The HTTP API uses the headers to authenticate the user and returns a success or failure along with the user and role information

Configuring Hasura to use webhooks

docker run -d -p 8080:8080 \
-e HASURA_GRAPHQL_DATABASE_URL=DATABASE_URL \
-e HASURA_GRAPHQL_ENABLE_CONSOLE=true \
-e HASURA_GRAPHQL_ADMIN_SECRET=secret \
-e HASURA_GRAPHQL_AUTH_HOOK=https://auth-web-hook.example.com \
hasura/graphql-engine:v1.0.0-alpha41

Hasura will then execute a GET request on https://auth-web-hook.example.com whenever it needs to authenticate a request. The API is expected to return 200 Ok if authentication has succeeded or 401 Unauthorized to deny authentication.

You can also configure the API to be a POST request by using the command line parameter --auth-hook-mode or the HASURA_GRAPHQL_AUTH_HOOK_MODE environment variable.

The exact request/response structure is described in the docs.

Session variables with webhooks

The API is expected to return a JSON response containing the session variables to use. For example if the API returns the response...

{
    "X-Hasura-User-Id": "25",
    "X-Hasura-Role": "user",
    "X-Hasura-Is-Owner": "true",
    "X-Hasura-Custom": "custom value"
}

... Hasura will extract the variables X-Hasura-User-Id, X-Hasura-Role, X-Hasura-Custom, and X-Hasura-Is-Owner.

Building apps that use webhook based authentication

There are community contributed boilerplates available for a few systems:

Hasura will treat a request as Unauthenticated access if:

  1. There is no webhook configured
  2. There is no Authorization header
  3. X-Hasura-Admin-Secret header is not set
  4. The role for unauthenticated access is configured

The role for unauthenticated access can be configured either by setting the command line flag --unauthorized-role or the environment variable HASURA_GRAPHQL_UNAUTHORIZED_ROLE.

This doc explains configuring permissions in unauthorized role.

We have covered the different authentication options available while executing a request. Hasura's authentication system is designed to be flexible. Hasura makes it easy to integrate whether you are using an third party auth provider like Auth0 or AuthGuardian or Firebase or rolling your own.

Note: Hasura Cloud comes with a pre-configured admin-secret. Try it out now and check out the docs to get started!

If you need help with setting up Auth with Hasura, ping us on Discord or tweet to us at @HasuraHQ!

Blog
08 Apr, 2019
Email
Subscribe to stay up-to-date on all things Hasura. One newsletter, once a month.
Loading...
v3-pattern
Accelerate development and data access with radically reduced complexity.