Search code examples
djangofacebookpython-social-auth

Facebook redirection with Django and python-social-auth


To locally test the ability to login in my django app with Facebook through python-social-auth, I have followed these steps:

  • define a mapping from 127.0.0.1 to www.florian.com in /etc/hosts
  • add http://www.florian.com:8000/login/facebook and http://www.florian.com:8000/complete/facebook in the field OAuth valid URI redirect in Facebook Login --> settings
  • run python manage.py runserver www.florian.com:8000

However, when accessing http://www.florian.com:8000/login/facebook, I get the following error:

Can't Load URL: The domain of this URL isn't included in the app's domains. To be able to load this URL, add all domains and subdomains of your app to the App Domains field in your app settings.

However when I check the validity of this URL with the field available in the Facebook Login --> settings, it is OK.

Here are my Django files:

urls.py:

from django.conf.urls import url, include
from django.contrib import admin
from rest_framework import routers
from backend import views
from webapp import views as webapp_views
from django.contrib.auth import views as auth_views


router = routers.SimpleRouter()
router.register(r'users', views.UserViewSet, 'User')
router.register(r'games', views.GameViewSet, 'Game')

urlpatterns = [
    url(r'^$', webapp_views.home, name='home'),
    url('', include('social_django.urls', namespace='social')),
# FACEBOOK login/registration from Web 
    url(r'^login/$', auth_views.login, name='login'),
    url(r'^logout/$', auth_views.logout, name='logout'),
    url('', include('social_django.urls', namespace='social')),
    url(r'^test/', webapp_views.test),
    url(r'^admin/', admin.site.urls),
    url(r'^connect/', views.CustomObtainAuthToken.as_view()),
    url(r'^membership_create/', views.MembershipCreate.as_view()), 
# Facebook login/registration from REST API
    url(r'^auth/connect_with_fb/', views.ConvertTokenViewWithData.as_view()),
# standard Django login/registration from REST API
    url(r'^auth/connect_with_credentials/', views.TokenViewWithData.as_view()),
    url(r'^debug/', views.UserLoginAndIdView.as_view()),
    url(r'^auth/', include('rest_framework_social_oauth2.urls'),

        )

]

urlpatterns += router.urls

login.html

{% block content %}
  <h2>Login</h2>
  <form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Login</button>
  </form>
  <br>
  <p><strong>-- OR --</strong></p>
  <a href="{% url 'social:begin' 'facebook' %}">Login with Facebook</a>

{% endblock %}

settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework.authtoken',
    'rest_framework',
    'oauth2_provider',
    'social_django',
    'rest_framework_social_oauth2',
    'backend',
    'webapp',
]

MIDDLEWARE = [
    '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',

    'social_django.middleware.SocialAuthExceptionMiddleware',  # <--

]

ROOT_URLCONF = 'WMC.urls'

SOCIAL_AUTH_URL_NAMESPACE = 'social'


TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [    os.path.join(BASE_DIR, 'templates'),
                     os.path.join(BASE_DIR, 'webapp/templates')],
        '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',
                'social_django.context_processors.backends',
                'social_django.context_processors.login_redirect',

            ],
        },
    },
]

WSGI_APPLICATION = 'WMC.wsgi.application'

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (

        'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
        'rest_framework_social_oauth2.authentication.SocialAuthentication',

    ),
}


AUTHENTICATION_BACKENDS = (

    # Facebook OAuth2
    'social_core.backends.facebook.FacebookAppOAuth2',
    'social_core.backends.facebook.FacebookOAuth2',

    # django-rest-framework-social-oauth2
    'rest_framework_social_oauth2.backends.DjangoOAuth2',

    # Django
    'django.contrib.auth.backends.ModelBackend',

)

# Django client_secret for OAuth Toolkit for django-rest-social-auth
CLIENT_SECRET = '***********************************************************************************'


# Facebook configuration
SOCIAL_AUTH_FACEBOOK_KEY = '***********'
SOCIAL_AUTH_FACEBOOK_SECRET = '*****************************'





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

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# Password validation
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Define SOCIAL_AUTH_FACEBOOK_SCOPE to get extra permissions from facebook. Email is not sent by default, to get it, you must request the email permission:
SOCIAL_AUTH_FACEBOOK_SCOPE = ['email']
SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = {
    'fields': 'id, name, email'
}


# Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True



# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/

STATIC_URL = '/static/'

Solution

  • Since the 1.6.0 version of the social_core library (part of python-social-auth), the field REDIRECT_STATE of FacebookOAuth2 backend has been set to False.

    As I was using the 1.5.0 version (where REDIRECT_STATE=True), and as the redirect_state changes each time in the call to the Facebook login, my app was not able to handle such a dynamic behavior.

    Thus, upgrading social_core to version 1.7.0 solves the issue.