# Source: https://docs.hypermode.com/dgraph/graphql/security/jwt.md

# Handle JWT Token

<Info>
  We're overhauling Dgraph's docs to make them clearer and more approachable. If
  you notice any issues during this transition or have suggestions, please
  [let us know](https://github.com/hypermodeinc/docs/issues).
</Info>

When deploying a GraphQL schema, the admin user can set a
`# Dgraph.Authorization` line at the bottom of the schema to specify how JWT
tokens present in the HTTP header requests are extracted, validated and used.

This line must start with the exact string `# Dgraph.Authorization` and be at
the bottom of the schema file.

## Configure JWT token handling

To configure how Dgraph should handle JWT token for `/graphql` endpoint add a
line starting with `# Dgraph.Authorization` and with the following parameters at
the very end of your GraphQL schema.

The `Dgraph.Authorization` object uses the following syntax:

```graphql
# Dgraph.Authorization {"VerificationKey":"<verification-key-here>","Header":"X-My-App-Auth","Namespace":"https://my.app.io/jwt/claims","Algo":"HS256","Audience":["aud1"],"ClosedByDefault":true}
```

`Dgraph.Authorization` object contains the following parameters:

* `Header` name of the header field used by the client to send the token.

  <Note>
    Don't use `Dg-Auth`, `X-Auth-Token` or `Authorization` headers which are
    used by Dgraph for other purposes.
  </Note>

* `Namespace` is the key inside the JWT that contains the claims relevant to
  Dgraph authorization.

* `Algo` is the JWT verification algorithm which can be either `HS256` or
  `RS256`.

* `VerificationKey` is the string value of the key, with newlines replaced with
  `\n` and the key string wrapped in `""`:
  * **For asymmetric encryption**: `VerificationKey` contains the public key
    string.
  * **For symmetric (secret-based) encryption**: `VerificationKey` is the secret
    key.

* `JWKURL`/`JWKURLs` is the URL for the JSON Web Key sets. If you want to pass
  multiple URLs, use `JWKURLs` as an array of multiple JWK URLs for the JSON Web
  Key sets. You can only use one authentication connection method, either JWT
  (`Header`), a single JWK URL, or multiple JWK URLs.

* `Audience` is used to verify the `aud` field of a JWT, which is used by
  certain providers to indicate the intended audience for the JWT. When doing
  authentication with `JWKURL`, this field is mandatory.

* `ClosedByDefault`, if set to `true`, requires authorization for all requests
  even if the GraphQL type doesn't specify rules. If omitted, the default
  setting is `false`.

When the `# Dgraph.Authorization` line is present in the GraphQL schema, Dgraph
uses the settings in that line to

* read the specified header in each HTTP request sent on the /graphql endpoint,
* decode that header as a JWT token using the specified algorithm
* validate the token signature and the audience
* extract the JWT claims present in the specified namespace and at the root
  level

These claims are accessible to any @auth schema directives (a GraphQL schema
directive specific to Dgraph) that are associated with GraphQL types in the
schema file.

See the [RBAC rules](./rbac-rules) and \[Graph traversal
rules]\(./graphtraversal-rules for details on how to restrict data access using
the @auth directive on a per-type basis.

### Require JWT token

To not only accept but to require the JWT token regardless of @auth directives
in your GraphQL schema, set option "ClosedByDefault" to true in the
`# Dgraph.Authorization` line.

## Working with authentication providers

`Dgraph.Authorization` is fully configurable to work with various authentication
providers. Authentication providers have options to configure how to generate
JWT tokens.

Here are some configuration examples.

### Clerk.com

In your clerk dashboard, Access `JWT Templates` and create a template for
Dgraph.

Your template must have an `aud` (audience), this is mandatory for Dgraph when
the token is verified using JWKURL.

Decide on a claim namespace and add the information you want to use in your RBAC
rules.

This example uses the `https://dgraph.io/jwt/claims` namespace and is retrieving
the user current organization, role (Clerk has currently two roles `admin` and
`basic_member`) and email.

This is our JWT Template in Clerk:

```json
{
  "aud": "dgraph",
  "https://dgraph.io/jwt/claims": {
    "org": "{{org.name}}",
    "role": "{{org.role}}",
    "userid": "{{user.primary_email_address}}"
  }
}
```

In the same configuration panel

* set the **token lifetime**
* copy the **JWKS Endpoint**

Configure your Dgraph GraphQL schema with the following authorization

```graphql
# Dgraph.Authorization {"header":"X-Dgraph-AuthToken","namespace":"https://dgraph.io/jwt/claims","jwkurl":"https://<>.clerk.accounts.dev/.well-known/jwks.json","audience":["dgraph"],"closedbydefault":true}
```

Note that

* **namespace** matches the namespace used in the JWT Template
* **audience** is an array and contains the **aud** used in the JWT token
* **jwkurl** is the **JWKS Endpoint** from Clerk

You can select the header to receive the JWT token from your client app,
`X-Dgraph-AuthToken` is a header authorized by default by Dgraph GraphQL API to
pass CORS requirements.

## Other Dgraph.Authorization Examples

To use a single JWK URL:

```graphql
# Dgraph.Authorization {"VerificationKey":"","Header":"X-My-App-Auth", "jwkurl":"https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com", "Namespace":"https://xyz.io/jwt/claims","Algo":"","Audience":["fir-project1-259e7", "HhaXkQVRBn5e0K3DmMp2zbjI8i1wcv2e"]}
```

To use multiple JWK URL:

```graphql
# Dgraph.Authorization {"VerificationKey":"","Header":"X-My-App-Auth","jwkurls":["https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com","https://dev-hr2kugfp.us.auth0.com/.well-known/jwks.json"], "Namespace":"https://xyz.io/jwt/claims","Algo":"","Audience":["fir-project1-259e7", "HhaXkQVRBn5e0K3DmMp2zbjI8i1wcv2e"]}
```

Using HMAC-SHA256 token in `X-My-App-Auth` header and authorization claims in
`https://my.app.io/jwt/claims` namespace:

```graphql
# Dgraph.Authorization {"VerificationKey":"secretkey","Header":"X-My-App-Auth","Namespace":"https://my.app.io/jwt/claims","Algo":"HS256"}
```

Using HMAC-SHA256 token in `X-My-App-Auth` header and authorization claims in
`https://my.app.io/jwt/claims` namespace:

```graphql
# Dgraph.Authorization {"VerificationKey":"-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----","Header":"X-My-App-Auth","Namespace":"https://my.app.io/jwt/claims","Algo":"RS256"}
```

### JWT format

The value of the JWT `header` is expected to be in one of the following forms:

* Bare token.\
  For example:

  ```txt
  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJodHRwczovL215LmFwcC5pby9qd3QvY2xhaW1zIjp7fX0.Pjlxpf-3FhH61EtHBRo2g1amQPRi0pNwoLUooGbxIho
  ```

* A Bearer token, e.g., a JWT prepended with `Bearer ` prefix (including
  space).\
  For example:
  ```txt
  Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJodHRwczovL215LmFwcC5pby9qd3QvY2xhaW1zIjp7fX0.Pjlxpf-3FhH61EtHBRo2g1amQPRi0pNwoLUooGbxIho
  ```

### Error handling

If ClosedByDefault is set to true, and the JWT is not present or if the JWT
token does not include the proper audience information, or is not properly
encoded, or is expired, Dgraph replies to requests on `/graphql` endpoint with
an error message rejecting the operation similar to:

```graphql
{
   "errors": [
       {
           "message": "couldn't rewrite query queryContact because a valid JWT is required but was not provided",
           "path": [
               "queryContact"
           ]
       }
   ],
   "data": {
       "queryContact": []
   },...
```

**Error messages**

* "couldn't rewrite query queryContact because a valid JWT is required but was
  not provided"
* "couldn't rewrite query queryMessage because unable to parse jwt token:token
  is expired by 5h49m46.236018623s"
* "couldn't rewrite query queryMessage because JWT `aud` value doesn't match
  with the audience"
* "couldn't rewrite query queryMessage because unable to parse jwt token:token
  signature is invalid"