Django-allauth: Twitter authentication stopped working

Created on 18 Jun 2018  路  10Comments  路  Source: pennersr/django-allauth

Quite some time ago, I added twitter OAuth integration using django-allauth. A few days ago, I noticed that whenever I try to login with twitter account, I am redirected to /accounts/twitter/login/?process=login with the following error:

Social Network Login Failure
An error occurred while attempting to login via your social network account.

No exceptions are thrown, making it harder to debug. This error page is rendered successfully with status code 200.

No changes were made to socialaccount fields (client id and secret key were left intact both in django admin and twitter app management interface). Other social accounts work just fine, I tested Google and Facebook. I am assuming that there was some change in twitter APIs, and if so, django-allauth may need to be updated, but I need help pinpointing the issue.

Is someone else experiencing the same problem?
I've been using django-allauth=0.33.0, but upgrading to 0.36.0 didn't solve the issue. I am on Django==1.11.6

Most helpful comment

@paramono We found out that we didn't have a callback for both the bare domain and www version. Maybe it will be the same for you.

For example allauth could be sending either of the following callback URLs to Twitter if you handle both bare and www under the same site.

  • https://[domain].com/accounts/twitter/login/callback/
  • https://www.[domain].com/accounts/twitter/login/callback/

All 10 comments

I am seeing this as well but with Shopify but unfortunately in my case it is user reported and I am having a hard time reproducing. Like the reporter, nothing has changed in code or configuration and I have confirmed that the callback URL is correct.

Edit: Something like this can be added to the DefaultSocialAccountAdapter to log an error when this occurs.

    def authentication_error(self,
                             request,
                             provider_id,
                             error=None,
                             exception=None,
                             extra_context=None):

        logger.error('Error in social authentication cycle. [Provider: {}]'.format(
            provider_id
        ))

        if exception:
            logger.exception(exception)

Alright I am reproducing this for Twitter as well. Here is the stack I was able to get with the logging above.

Traceback (most recent call last):
  File "/(snip)/python3.6/site-packages/allauth/socialaccount/providers/oauth/views.py", line 69, in dispatch
    return client.get_redirect(auth_url, auth_params)
  File "/(snip)/python3.6/site-packages/allauth/socialaccount/providers/oauth/client.py", line 145, in get_redirect
    request_token = self._get_request_token()
  File "/(snip)/python3.6/site-packages/allauth/socialaccount/providers/oauth/client.py", line 80, in _get_request_token
    self.request_token_url))
allauth.socialaccount.providers.oauth.client.OAuthError: Invalid response while obtaining request token from "api.twitter.com".

@paramono We found out that we didn't have a callback for both the bare domain and www version. Maybe it will be the same for you.

For example allauth could be sending either of the following callback URLs to Twitter if you handle both bare and www under the same site.

  • https://[domain].com/accounts/twitter/login/callback/
  • https://www.[domain].com/accounts/twitter/login/callback/

@ivanvenosdel

That would be very strange. I use bare domain only; www version is 301 redirected to the bare one and is usually never accessed. In twitter developer settings, I pointed all urls to the bare domain.

Also, I use Django "sites" framework. I have only one site there, with bare domain. Shouldn't allauth use django sites for determining URL? Besides, it worked earlier. Why would it break if callback URLs weren't changed neither in Django configuration/models, nor in Twitter dev settings?

@ivanvenosdel Did adding these two callback urls fixed the issue for you?

I have the same concern as @paramono ... I tried to add the additional callback, but it didn't work for me.

No Twitter connection working for a few days...

@paramono

Shouldn't allauth use django sites for determining URL?

Near as I can tell allauth uses reverse to get the relative URL and from there it uses the request to make it an absolute URL. So whatever domain the user started with rather than sites. I think that is probably for the best so that the user isn't switching domains mid-oauth.
https://github.com/pennersr/django-allauth/blob/cfc5112bf474af2cbb16e4b4a36708e8949a2105/allauth/socialaccount/providers/oauth/views.py#L61
https://github.com/pennersr/django-allauth/blob/0367b51514e592db011511e420570789c7d1df75/allauth/socialaccount/providers/oauth/client.py#L71

Besides, it worked earlier. Why would it break if callback URLs weren't changed

In our case it was either that we hadn't had users using the bare domain before or, more likely, we didn't notice until I found out how to log the errors. So because we tested it in the past under the right URL to start, it looked like all was good and then later when we tested it with the bare domain "all of the sudden" it looked broken even though we probably had one path broken all along.

I use bare domain only; www version is 301 redirected to the bare one and is usually never accessed.

The problem you are experiencing is likely different then my own but to be sure I suggest you confirm that a user starting with www or bare is indeed broken in the same way.

If that is the case, I suggest creating a fork and adding some code that attaches the response (as an attribute, not in the message) to the OauthError that allauth raises. That would allow you to then log the twitter response status code and text using the approach I pasted above. The Twitter response text seems to make the problem a whole lot more obvious.
https://github.com/pennersr/django-allauth/blob/0367b51514e592db011511e420570789c7d1df75/allauth/socialaccount/providers/oauth/client.py#L77

I also think that including the response as an attribute on the exception would be a nice change that penners may approve if you ever wanted to turn it into a PR.

@tanzaho Yes it did, but again the issues you two are experiencing may be different. I suggest the approach I describe above to both confirm that your problem is different than mine and start on diagnosing the true issue.

What I can confirm is that the allauth Twitter flow is not broken for everyone as my issue was one of Twitter misconfiguration on our part and is now working.

The change is probably related to this announcement : https://blog.twitter.com/developer/en_us/topics/tools/2018/Sign-in-with-Twitter-users-must-whitelist-callback-URLs.html

When I updated my callback yesterday, they didn't immediately worked, but when I tried again today, it worked. So there was maybe some propagation time.

All is back in order for me. I guess that people will need to update their callback URL on Twitter if they see this thread. (from my point of view, we could close this issue).

@tanzaho Thanks for the useful link. It also refers to this page:
https://twittercommunity.com/t/action-required-sign-in-with-twitter-users-must-whitelist-callback-urls/105342

Where I found the following:

In 30 days, we will begin enforcing the whitelist such that any URL not added to the whitelist will fail.

And then I realized what my problem was. I defined by callback URL as

  • https:/{{doman}}/accounts/twitter/login/callback/

But my website is multilingual, it uses i18n for generating URLs for each language. If you access any page without language code in the URL, it will redirect you to the appropriate language version (for example, /accounts/twitter/login/callback/ would redirect you to /en/accounts/twitter/login/callback/ or some other language if appropriate).

This approach of specifying callback URL without the language code (and relying on i18n redirects) used to work fine with twitter, but after they introduced this new callback whitelist policy, redirecting became illegal.

In order to fix this, I removed the original URL from callback list, and added a callback for each language version, for example:

  • https:/{{doman}}/en/accounts/twitter/login/callback/
  • https:/{{doman}}/de/accounts/twitter/login/callback/
  • https:/{{doman}}/fr/accounts/twitter/login/callback/

And after that, twitter auth started working again.


So I think this particular issue can be closed. However, the solution was not too obvious when I first encountered the problem.

@pennersr Perhaps I should update the docs to explain that for i18n websites you may need to define additional/language-specific callbacks if you plan to use certain providers?

Try with both HTTP and HTTPS too. This was my problem.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

peterhn picture peterhn  路  4Comments

slimaidarismail picture slimaidarismail  路  3Comments

FSE-DEV picture FSE-DEV  路  5Comments

nlubega picture nlubega  路  4Comments

blueyed picture blueyed  路  5Comments