0

I’m currently trying to create a web interface with AngularJS using Django as a backend and I get the usual CORS error: XMLHttpRequest cannot load http://fatboyapi.ddns.net:8000/o/revoke_token/?client_id=xxx&client_secret=xxx&token=xxxxxxxx. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://fatboy.ddns.net:8000' is therefore not allowed access..

When the flag CORS_ORIGIN_ALLOW_ALL is set to True everything works, but it is not safe obviously. The end point I’m calling is o/token/ provided by django-oauth-toolkit

I added these to links to my whitelist. 'http://fatboyapi.ddns.net:8000', 'http://fatboy.ddns.net:8000'

I don’t get any error when I use restclient on firefox or Postman combined with CORS_ORIGIN_ALLOW_ALL = False

the address I use to call my api is 'http://fatboy.ddns.net:8000'

Here are the packages I’m using with Django

boto==2.38.0
contextlib2==0.4.0
Django==1.9
django-braces==1.8.1
django-cors-headers==1.1.0
django-custom-user==0.5
django-debug-toolbar==1.4
django-guardian==1.3.2
django-indexer==0.3.0
django-oauth-toolkit==0.9.0
django-paging==0.2.5
django-storages==1.1.8
django-templatetag-sugar==1.0
djangorestframework==3.3.1
docutils==0.12
eventlet==0.17.4
greenlet==0.4.9
lockfile==0.12.2
oauthlib==1.0.1
Pillow==2.9.0
psycopg2==2.6.1
six==1.10.0
sqlparse==0.1.18
wheel==0.24.0

This is my settings.py

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'corsheaders',
    'custom_user',
    'guardian',
    'rest_framework',
    'oauth2_provider',
    'scheduleauthentication',
    'punchclock',
    'debug_toolbar',
)

AUTH_USER_MODEL = 'custom_user.EmailUser'

ANONYMOUS_USER_ID = -1

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'guardian.backends.ObjectPermissionBackend',
)

MIDDLEWARE_CLASSES = (
    'debug_toolbar.middleware.DebugToolbarMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
)

ROOT_URLCONF = 'punchclock.urls'

CORS_ORIGIN_ALLOW_ALL = False

CORS_ORIGIN_WHITELIST = (
    'https://fatboyapi.ddns.net',
    'https://fatboy.ddns.net',
    'http://fatboyapi_i.ddns.net',
    'http://fatboy_i.ddns.net',
    'http://fatboyapi.ddns.net:8000',
    'http://fatboy.ddns.net:8000'
)

CORS_ALLOW_CREDENTIALS = False

CORS_ALLOW_METHODS = (
        'GET',
        'POST',
        'PUT',
        'PATCH',
        'DELETE',
        'OPTIONS'
    )

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        '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',
            ],
        },
    },
]

WSGI_APPLICATION = 'punchclock.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases

DATABASES = {
    'default': {
        'NAME': 'pc',
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'HOST': 'localhost',
        'USER': 'postgres',
        'PASSWORD': 'fatboy',
        'PORT': '5432',
    }

}
#REST-FRAMEWORK
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'oauth2_provider.ext.rest_framework.OAuth2Authentication',
    )
}

Thank you !

falsetru
  • 357,413
  • 63
  • 732
  • 636
NOaMTL
  • 193
  • 1
  • 4
  • 13
  • What's the problem? You say that it's working in "Firefox and Postman combined with..." :) – Skaparate Jan 15 '16 at 01:43
  • I would like to put : CORS_ORIGIN_ALLOW_ALL to FALSE, and have my app working without the CORS error. Because with this setting, it is only working with postman, it is not in my app (i get the error i did write at the beginning of the question). – NOaMTL Jan 15 '16 at 02:14

1 Answers1

1

Using CORS headers you can restrict which clients are allowed to make requests and which methods are allowed.

Access-Control-Allow-Origin: http://siteA.com

Access-Control-Allow-Methods: GET, POST, PUT

there are other headers too, Google it :)

Alternatively, is Angular running on Apache or Node or something? If so, then you could make the request to the same domain such as http://yourangulardomain.com/api/request/that/i/want/to/go/to/my/django/server

and then put a rewrite rule in your Apache/Node config to rewrite the request. This will circumvent the cross origin problem.

A similar rewrite rule used on Node (which serves Angular) using the npm module connect-modrewrite (which is based heavily on Apache rewrite rules) is ...

middleware: [
      rewrite([
        '^/api/(.*)$ http://10.20.1.20:9100/$1 [P]',
        '^[^\\.]*$ /index.html [L]'
      ])
    ]

This basically sends requests containing /api in the URL to a diff server but routes everything else to index.html

Not sure why this doesn't interfere with requests for CSS files and the like though!!

Hope that helps steer you anyway :)

danday74
  • 52,471
  • 49
  • 232
  • 283
  • Hello, thanks for the reply. My understanding of this is that by adding an element to my cors_origin_whitelist(e.g. fatboy.ddns.net:8000) Django will automatically send the following header to the client "Access-control-allow-origin: fatboy.ddns.net:8000". That header will make it possible to display on my browser the content of the http response. At the moment, this is the response header I get: Cache-Control → no-store Content-Type → application/json Date → Sat, 16 Jan 2016 05:15:01 GMT Pragma → no-cache Server → WSGIServer/0.2 CPython/3.4.2 X-Frame-Options → SAMEORIGIN (postman) – NOaMTL Jan 16 '16 at 05:25
  • I recently did a configuration with a proxy where I added the Access-control-allow-origin and AngularJS was able to display the result without a fuss. Now, what I'm not understanding is why is it that Django won't send me that header despite the fact that I added my domain name on the white list. Is there something specific that I need to send with AngularJS? Or maybe I need to configure something else in the settings.py file. Thanks! – NOaMTL Jan 16 '16 at 07:34
  • If the same headers are sent in the request then the response should be the same. I would investigate what headers angular is sending and compare that to the headers that are being sent on a successful postman request. Use curl to test various headers. Also, is angular making an OPTIONS pre-flight request? The OPTIONS request is made by default when you do a cross domain POST or PUT even if you don't request it. If the OPTIONS request fails then your actual request (POST or PUT) will never be made. Look in your browsers NET tab to see if Angular is making an OPTIONS request. – danday74 Jan 18 '16 at 11:03
  • @NOaMTL were you ever able to solve the issue? I am facing a similar problem- https://stackoverflow.com/questions/50846958/cors-header-not-working-for-django-backend-angular-frontend – Subzero Jun 18 '18 at 22:36