

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="robots" content="NONE,NOARCHIVE">
<title>403 Forbidden</title>
<style type="text/css">
html * { padding:0; margin:0; }
body * { padding:10px 20px; }
body * * { padding:0; }
body { font:small sans-serif; background:#eee; }
body>div { border-bottom:1px solid #ddd; }
h1 { font-weight:normal; margin-bottom:.4em; }
h1 span { font-size:60%; color:#666; font-weight:normal; }
#info { background:#f6f6f6; }
#info ul { margin: 0.5em 4em; }
#info p, #summary p { padding-top:10px; }
#summary { background: #ffc; }
#explanation { background:#eee; border-bottom: 0px none; }
</style>
</head>
<body>
<div id="summary">
<h1>Forbidden
<span>(403)</span>
</h1>
<p>CSRF verification failed. Request aborted.</p>
</div>
<div id="info">
<h2>Help</h2>
<p>Reason given for failure:</p>
<pre>
CSRF token missing or incorrect.
</pre>
<p>In general, this can occur when there is a genuine Cross Site Request Forgery, or when
<a
href="https://docs.djangoproject.com/en/1.11/ref/csrf/">Django's
CSRF mechanism</a> has not been used correctly. For POST forms, you need to
ensure:
</p>
<ul>
<li>Your browser is accepting cookies.</li>
<li>The view function passes a
<code>request</code> to the template's
<a
href="https://docs.djangoproject.com/en/dev/topics/templates/#django.template.backends.base.Template.render">
<code>render</code>
</a>
method.
</li>
<li>In the template, there is a
<code>{% csrf_token
%}</code> template tag inside each POST form that
targets an internal URL.
</li>
<li>If you are not using
<code>CsrfViewMiddleware</code>, then you must use
<code>csrf_protect</code> on any views that use the
<code>csrf_token</code>
template tag, as well as those that accept the POST data.
</li>
<li>The form has a valid CSRF token. After logging in in another browser
tab or hitting the back button after a login, you may need to reload the
page with the form, because the token is rotated after a login.</li>
</ul>
<p>You're seeing the help section of this page because you have
<code>DEBUG =
True</code> in your Django settings file. Change that to
<code>False</code>,
and only the initial error message will be displayed.
</p>
<p>You can customize this page using the CSRF_FAILURE_VIEW setting.</p>
</div>
</body>
</html>
Include this on your URLS
url(r'^graphql', csrf_exempt(GraphQLView.as_view(graphiql=True))),
This isn't a graphql issue, this is a django security measure, you need to include a csrf token with the request to prevent xss attacks. While you can disable the csrf for testing as @NikosVlagoidis mentioned, I would not recommend it for production.
As @audiolion mentions, you should only use it if you want to test your graphql backend with postman. For production, you should read about csrf token and how to implement it on a front-end
Very useful for now while I'm experimenting and don't want to spend time learning about Django CSRF token.
@NikosVlagoidis @audiolion How should implement proper GraphQL support in production? I don't want to create a UI form, but rather support server-to-server API calls. AFAIK, CSRF is only for UI forms, I don't understand why CSRF token is recommended for production even without a form ?
@ceefour isn't @NikosVlagoidis comment helpful? basically with:
python
url(r'^graphql', csrf_exempt(GraphQLView.as_view(graphiql=True))),
you're telling django to not use csrf protection on the GraphQL endpoint, which is fine, since it is an API.
EDIT:
CSRF tokens are required in production by default because django doesn't know which POST request is for a form and which isn't. Also CSRF might be useful in the case you want to use the GraphQL endpoint only on your website (so having the token is an additional security measure). But for you case it is totally fine to remove the CSRF token check in production :)
@patrick91 Thanks for the clarification. 👍
I am experience this problem when using with graphiql and need to use csrf_exempt to get it run
django==2.2.6
graphene-django==2.6.0
graphene==2.1.8 # via graphene-django
graphql-core==2.2.1 # via graphene, graphene-django, graphql-relay
graphql-relay==2.0.0 # via graphene
Sorry about necroposting, but this is one of the top results when searching for CSRF issues so hopefully it helps someone.
If you don't want to disable CSRF protection, you can use a GET request insted of a POST. Using a POST request:
$ curl -g -X POST -H "Content-Type: application/json" -d \
'{ "query": "{ allFoo { bar, baz} }" }' https://localhost/graphql/
Equivalent request using GET:
$ curl -g -k 'https://localhost/graphql/?query={allFoo{bar,baz}}'
@patryk-tech Your method works fine, and if you only use your Graphql endpoint for query only, then you shouldn't look further. However, there is a limitation.
GET methods for anything else than queryIf one wants to implements this workaround and is also using Graphql for mutations, I would not recommend it. It has been established as a standard that GET requests must not alter the state of the server, nor the database, and mutations are, most of the time, used for altering the state of one or another (probably only the database, since your backend app should be stateless).
Note that you could also use query methods to alter the state of your backend, but, again, this would be against the established standard, as explained in the grapqhl documentation:
[...] In REST, any request might end up causing some side-effects on the server, but by convention it's suggested that one doesn't use GET requests to modify data. GraphQL is similar - technically any query could be implemented to cause a data write. However, it's useful to establish a convention that any operations that cause writes should be sent explicitly via a mutation.
csrf_exempt decorator?To give hints to people wondering how bad it is to get rid of the default CSRF checks, here is my two cents explanation.
A service is exposed to CSRF attacks when the authentication parameters are automatically sent by the browser, which is the case with the default Django's authentication system, based on sessions.
If you use your Django app only as an API backend, chances are that you rely on another authentication mechanism, such as DRF's TokenAuthentication or some kind of JWT implementation.
Basically, these authentication systems are immune to CSRF attacks, because if a malicious website wants to access your server on behalf of your users — which is what CSRF is all about —, it won't be able to set the Authorization HTTP header expected by your server to actually authenticate the request (provided that you stored the token securely, in a cookie only accessible by your front application domain...).
tl;dr — If your Graphql endpoint is accessible only by authenticated users and your authentication system does not rely on Django's sessions, it's ok to exempt your endpoint from CSRF checking.
Hope this helps.
Most helpful comment
Include this on your URLS
url(r'^graphql', csrf_exempt(GraphQLView.as_view(graphiql=True))),