marknotfound | the blog

mark (he/him) is a software engineer, photographer, runner, and other things too sometimes.

How to disable GraphQL introspection in Graphene

Introspection in GraphQL allows an attacker to learn everything about your API's schema including queries, mutations, types, fields, and directives. It is therefore important to disable introspection on production GraphQL APIs.

Background

When searching Google for how to tackle disabling introspection in Graphene, the top results recommend a custom middleware approach. However, this isn't very efficient since GraphQL middlewares run for every field in a given operation. If you have any queries with a subtantial amount of fields, it's just a waste of time to check for introspection on every single field to be resolved.

The Graphene/GraphQL Way

There is a simpler way and it involves GraphQL validation rules. In fact, Graphene has a section of their docs showing exactly how to do it this way, but it's at the bottom of Google. If you want, you can stop reading this and just click that link. I won't be offended.

Graphene ships with a validation rule DisableIntrospection. This can be passed to the schema validator like this:

from graphql import validate
from graphene.validation import DisableIntrospection
from my_graphql import schema

errors = validate(
schema=schema,
rules=(DisableIntrospection,)
)

With Django

In my case, I'm using a custom view for the GraphQL endpoint which inherits from graphene_django.views.GraphQLView and happens to override GraphQLView.execute_graphql_request which in turn calls validate. I only want to disable introspection in production, so to conditionally apply the DisableIntrospection rule I use a partial:

from functools import partial
from graphql import validate
from graphene.validation import DisableIntrospection
from graphene_django.views import GraphQLView
from django.conf import settings

if settings.PRODUCTION:
validate = partial(
validate,
rules=(DisableIntrospection,)
)

class MyGraphQLView(GraphQLView)
def execute_graphql_request(self, *args, **kwargs):
# ...
errors = validate(
self.schema.graphql_schema,
document
)
# ...
return self.schema.execute()

That's it. No middlewares required. Go forth and lock down your GraphQL APIs!

Go back