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.
- Introduction
- Authentication using admin secret
- Authentication using JSON Web Tokens (JWT)
- Authentication using webhooks
- Unauthenticated access
- Summary
Hasura supports 4 methods of authentication
- Admin secret based authentication: Use this method if you are doing server to server communication and the client is a trusted client.
- 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
- Webhook based authentication: Use this method if you need to roll out a custom authentication solution.
- 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:
- Hasura is configured with an admin password on startup
- When making an API request the client passes the admin password in the header X-Hasura-Admin-Secret
- 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
while starting Hasura. Hasura docs describe the instructions for doing this on Heroku, on Docker, and on Kubernetes. HASURA_GRAPHQL_ADMIN_SECRET
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:
- An end-user is authenticated on the app by your authentication server
- On successful authentication, the authentication server returns a JWT to the app with the user and role information embedded in the claims section
- The app passes the JWT in the
Authorization
header to Hasura - 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:
- Auth0: Auth0 JWT Integration with Hasura GraphQL engine
- AuthGuardian: OneGraph’s AuthGuardian JWT Integration with Hasura GraphQL engine
- AWS Cognito: Using AWS Cognito for authentication
- Firebase: A tutorial for using Firebase to add authentication and authorization to a realtime Hasura app
- NextJS apps: Add Authentication and Authorization to Next.js 8 Serverless Apps using JWT and GraphQL
Here is how webhook based auth works:
- 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.
- Hasura calls a pre-configured webhook. Hasura will forward the headers to the API.
- 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:
- There is no webhook configured
- There is no
Authorization
header X-Hasura-Admin-Secret
header is not set- 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!
08 Apr, 2019
7 MIN READ