Reputation: 43
I'm working on a project using Django as API backend (hosted on localhost:8000) and React (hosted on localhost:3000) as frontend. My plan is to host them on different servers in production as well. I'm currently trying to set the CSRF token in the browser cookies tab using the "ensure_csrf_cookie" method decorator. While the javascript API call seems to work and returns the response, no cookie is set in my cookie tab (tested in different browsers). However, the weird thing is that when I type in the CSRF token URL directly in the browser, the cookie is set. This leads me to believe it's not working due to some cross-origin issues. So I've tried many different settings in my settings.py file without success.
Django View:
@method_decorator(ensure_csrf_cookie, name='dispatch')
class GetCSRFToken(APIView):
permission_classes = (permissions.AllowAny, )
def get(self, request, format=None):
return Response ({ "success": "CSRF cookie set"})
React:
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== "") {
const cookies = document.cookie.split(";");
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) === name + "=") {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
async function fetchCsrfToken() {
try {
const res = await fetch(`http://127.0.0.1:8000/accounts/csrf_cookie`, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
});
if (!res.ok) {
console.log("Problem");
} else {
const context = await res.json();
console.log(context);
}
} catch (e) {
// showMessage("Error: Unexpected error has occurred!", "Error");
}
}
const CSRFToken = () => {
const [csrftoken, setcsrftoken] = useState("");
useEffect(() => {
console.log("useEffect");
fetchCsrfToken();
setcsrftoken(getCookie("csrftoken"));
}, []);
return (
<>
<input
className="csrfmiddlewaretoken"
type="hidden"
name="csrfmiddlewaretoken"
value={csrftoken}
/>
</>
);
};
Django Settings:
from pathlib import Path
import os
BASE_DIR = Path(__file__).resolve().parent.parent
DEBUG = True
ALLOWED_HOSTS = []
MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads/')
MEDIA_URL = '/uploads/'
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'corsheaders',
'groups',
'registration',
'accounts',
'channels',
'allauth',
'allauth.account',
'allauth.socialaccount',
]
AUTH_USER_MODEL = 'accounts.User'
ACCOUNT_FORMS = {'signup': 'registration.forms.CustomSignUpForm'}
LOGIN_URL = '/registration/login/'
LOGIN_REDIRECT_URL = '/'
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'build')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.IsAuthenticated"
],
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework.authentication.SessionAuthentication",
]
}
CSRF_TRUSTED_ORIGINS = ['https://*.127.0.0.1', 'http://localhost:3000']
CORS_ORIGIN_WHITELIST = ['https://*.127.0.0.1', 'http://localhost:3000']
CORS_ALLOW_HEADERS = [
'accept',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
]
CORS_ORIGIN_ALLOW_ALL=True
CORS_ALLOW_CREDENTIALS = False
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("localhost", 6379)],
},
},
}
Upvotes: 4
Views: 572