If you will have a look at OAuth examples on twitter apiwiki there are already examples available to use Sign in with Twitter with Django, so why this new howto and example code. Because being a perfectionist I like things to be the standard way, so for authentication django allows you to specify your own customized authentication backends. I thought why should not that be utilized to authenticate the Django User object with twitter.
There are few pre-requisites listed below in the order they are needed:
- simplejson
- oauth
- python-twitter
- oauth-python-twitter
- TwitterBackend from djangosnippets.org
This guide assumes that simplejson, oauth, python-twitter and oauth-python-twitter are already on your python path.
1. Now create a new Django project: twitterapp
$ django-admin startproject
2. Change to the project directory.
3. Now start a new app inside the project
$ python manage.py startapp twitterauth
4. Create a new directory: backends
$ mkdir backends
5. Change to the backends directory and create 2 new empty files.
$ cd backends
$ touch __init__.py
$ touch twitteroauth.py
6. Copy the code from TwitterBackend into the empty file: twitteroauth.py
7. Now configure your settings.py and add/edit following configuration variables
CONSUMER_KEY = "Your consumer key from twitter" CONSUMER_SECRET = "You consumer secret from twitter" AUTHENTICATION_BACKENDS = ( 'backends.twitteroauth.TwitterBackend', 'django.contrib.auth.backends.ModelBackend', ) AUTH_PROFILE_MODULE = "twitterauth.UserProfile" |
8. Now goto the twitterauth app directory and create a UserProfile module and post save signal processor as follows:
from django.db import models from django.db.models.signals import post_save from django.contrib.auth.models import User class UserProfile(models.Model): user = models.ForeignKey(User) access_token = models.CharField(max_length=255, blank=True, null=True, editable=False) profile_image_url = models.URLField(blank=True, null=True) location = models.CharField(max_length=100, blank=True, null=True) url = models.URLField(blank=True, null=True) description = models.CharField(max_length=160, blank=True, null=True) def __str__(self): return "%s's profile" % self.user def create_user_profile(sender, instance, created, **kwargs): if created: profile, created = UserProfile.objects.get_or_create(user=instance) post_save.connect(create_user_profile, sender=User) |
9. Now modify your views.py in twitterauth app directory as following:
from django.conf import settings from django.http import HttpResponseRedirect, HttpResponse from django.contrib.auth import login, authenticate from oauthtwitter import OAuthApi import oauth CONSUMER_KEY = getattr(settings, 'CONSUMER_KEY', 'YOUR_KEY') CONSUMER_SECRET = getattr(settings, 'CONSUMER_SECRET', 'YOUR_SECRET') def twitter_signin(request): twitter = OAuthApi(CONSUMER_KEY, CONSUMER_SECRET) request_token = twitter.getRequestToken() request.session['request_token'] = request_token.to_string() signin_url = twitter.getSigninURL(request_token) return HttpResponseRedirect(signin_url) def twitter_return(request): request_token = request.session.get('request_token', None) # If there is no request_token for session, # means we didn't redirect user to twitter if not request_token: # Redirect the user to the login page, # So the user can click on the sign-in with twitter button return HttpResponse("We didn't redirect you to twitter...") token = oauth.OAuthToken.from_string(request_token) # If the token from session and token from twitter does not match # means something bad happened to tokens if token.key != request.GET.get('oauth_token', 'no-token'): del request.session['request_token'] # Redirect the user to the login page return HttpResponse("Something wrong! Tokens do not match...") twitter = OAuthApi(CONSUMER_KEY, CONSUMER_SECRET, token) access_token = twitter.getAccessToken() request.session['access_token'] = access_token.to_string() auth_user = authenticate(access_token=access_token) # if user is authenticated then login user if auth_user: login(request, auth_user) else: # We were not able to authenticate user # Redirect to login page del request.session['access_token'] del request.session['request_token'] return HttpResponse("Unable to authenticate you!") # authentication was successful, use is now logged in return HttpResponse("You are logged in") |
10. Add the following 2 lines to urls.py at correct location.
url('^login/$', twitter_signin, name='login'), url('^return/$', twitter_return, name='return'), |
11. Now start the django devevelopment server
$ python manage.py runserver
12. Goto http://localhost:8000/login and you will be redirected to twitter for authentication, and if you have done everything correctly then after Allowing your application you will see the message that your are logged in.
I ran across your blog and it is exactly what I am looking for. I was following your steps and have ran into an issue with the oauth plugin it seems. I was wondering if you have any idea about the following message:
>>> import oauth
>>> import twitter
>>> import oauthtwitter
Traceback (most recent call last):
File “”, line 1, in
File “/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/oauthtwitter.py”, line 30, in
class OAuthApi(Api):
File “/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/oauthtwitter.py”, line 148, in OAuthApi
def _signRequest(self, req, signature_method=oauth.OAuthSignatureMethod_HMAC_SHA1()):
AttributeError: ‘module’ object has no attribute ‘OAuthSignatureMethod_HMAC_SHA1’
oAuth imports fine but when I try to import oauthtwitter. I get that error from command line. Any help would be glady appreciated.
Dev Box:
OS X 10.5
Python 2.5.4
Django 1.0.2
Thanks in advance
[Reply]
Hameedullah Khan Reply:
May 10th, 2009 at 7:29 am
Hello Eric,
I am glad you were able to find what you needed. You really do not have to import oauth and twitter unless you want to use them directly.
So, you can just do:
import oauthtwitter
The error is I think because you might be using some other version of the oauth. Kindly please download the version of oauth that is listed at the top of the post and use that version. Because twitter only support HMAC-SHA1 based oauth signatures. So you have to have that class in your implementation of oauth. The version that is listed above has it.
I hope it will help you.
[Reply]
Joseph Turian Reply:
July 25th, 2009 at 5:03 pm
I had this problem too. I get it when I used setuptools to install an egg of ouath. Instead, just copy oauth.py into your Python path and it will work fine.
[Reply]
Thank you very much for the nice implementaion.
I stated using it and i like it very much.
I keep running into one strange issue:
Every once in a while a user gets the following when returning from twitter error:
“We didn’t redirect you to twitter…”
Which means that for some reason there was no ‘request_token’ key in the session.
Any ideas what may cause this?
[Reply]
Hameedullah Khan Reply:
May 26th, 2009 at 6:41 pm
Hmm.. this is strange, if user is properly redirected to twitter as in twitter_signin view then they should have request_token in their session.
Might be user’s browser clearing up cookies?
There is nothing else I can think of right now, but I will look into it and will let you know if I will find something, but I didn’t face this yet on my end.
[Reply]
godswearhats Reply:
February 16th, 2010 at 5:53 am
I’m seeing this problem too. The session in the twitter_return method has a different session_key to the one in the twitter_signin method.
Using Firefox (or Safari) I see that a cookie gets created with the twitter_signin session key, but not with the twitter_return key. I also have two sessions in my db. Still no closer to solving it though.
[Reply]
godswearhats Reply:
February 16th, 2010 at 6:59 am
OK, I think I’ve cracked this issue. What’s happening is that my domain that I’m requesting from and the domain that I’m telling twitter to return to are different, thus setting two different cookies (and not restoring the correct session).
In my case this was ‘localhost’ vs ‘127.0.0.1’ but it could also be ‘www.example.com’ vs ‘example.com’. Check your domain in your location bar, and also in your twitter app config.
Hope this helps!
[Reply]
DanInCambridge Reply:
September 12th, 2009 at 1:52 pm
This is also happening to me. I am sniffing the traffic and I can’t see anything weird, twitter just doesn’t seem to be setting the request_token. I’ve tried multiple different twitter users and different browsers.
[Reply]
Hi,
I’m having an issue with the implementation. I get the following error:
AttributeError at /login/
‘OAuthApi’ object has no attribute ‘_default_params’
Exception Location: oauthtwitter.py in _FetchUrl, line 70
And for return I get No un-authed token cookie.
Any assistance would be greatly appreciated.
[Reply]
Great work and had a question. I’m new to Django. I did not understand step 8 where you state “create a UserProfile module and post save signal processor as follows:”
Does this mean
1.create a module UserProfile.py
2.Add the below code to UserProfile.py
or
1.Create a module UserProfile.py
2.Add the below code to a file Models.py and do sync db
[Reply]
Hameedullah Khan Reply:
June 11th, 2009 at 3:27 pm
Thanks for pointing that out, that should be create UserProfile model. Will fix it now.
[Reply]
Joseph Turian Reply:
July 25th, 2009 at 6:56 pm
I am still very confused by where UserProfile goes and the specifics here.
I get a similar error as here: http://groups.google.com/group/django-users/browse_thread/thread/8494cd87bf181018/e73fed4cdbd80a4e
and I can’t figure out how to solve it.
[Reply]
Srinivassan Pattabiraman Reply:
June 19th, 2011 at 2:51 am
I created a model UserProfile and pasted the code there, first in the models.py and next removed it and put it in UserProfile.py ran syncdb as well. Still I am getting the same error.
Here is the traceback
Traceback:
File “/var/www/tweetapp/django/core/handlers/base.py” in get_response
111. response = callback(request, *callback_args, **callback_kwargs)
File “/var/www/tweetapp/twitterauth/views.py” in twitter_return
44. auth_user = authenticate(access_token=access_token)
File “/var/www/tweetapp/django/contrib/auth/__init__.py” in authenticate
55. user = backend.authenticate(**credentials)
File “/var/www/tweetapp/backends/twitteroauth.py” in authenticate
50. userprofile = user.get_profile()
File “/var/www/tweetapp/django/contrib/auth/models.py” in get_profile
380. raise SiteProfileNotAvailable(‘Unable to load the profile ‘
Exception Type: SiteProfileNotAvailable at /return/
Exception Value: Unable to load the profile model, check AUTH_PROFILE_MODULE in your project settings
[Reply]
Thanks for this!
Everything seems to work except for when i return from twitter i get an exception (type ProgrammingError) “can’t adapt ” in backends/twitteroauth.py line 57 ( ” userprofile.save() “)
Anyone got some ideas how to fix this?
Thanks in advance!!
[Reply]
Ben Reply:
December 18th, 2009 at 8:57 pm
Hi I have the same issue. Did you manage to resolve this?
[Reply]
I am trying to use this implementation and have gotten pretty far, except that when twitter redirects back, I am getting an error because the UserProfile table is not in the database. Perhaps I am not reading the instructions correctly, but I created the file called UserProfile.py in the twitterauth directory. But when I run manage.py syncdb, it is not creating the UserProfile. Obviously I’m missing something. Can anyone help?
Thanks,
JoeCascio
ps. Here’s the traceback:
Traceback Switch to copy-and-paste view
/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/core/handlers/base.py in get_response
response = callback(request, *callback_args, **callback_kwargs) …
▶ Local vars
/Users/joecascio/projects/utwility/../utwility/twitterauth/views.py in twitter_return
auth_user = authenticate(access_token=access_token) …
▶ Local vars
/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/contrib/auth/__init__.py in authenticate
user = backend.authenticate(**credentials) …
▶ Local vars
/Users/joecascio/projects/utwility/backends/twitteroauth.py in authenticate
userprofile = user.get_profile() …
▶ Local vars
/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/contrib/auth/models.py in get_profile
if not hasattr(self, ‘_profile_cache’):
from django.conf import settings
if not getattr(settings, ‘AUTH_PROFILE_MODULE’, False):
raise SiteProfileNotAvailable
try:
app_label, model_name = settings.AUTH_PROFILE_MODULE.split(‘.’)
model = models.get_model(app_label, model_name)
self._profile_cache = model._default_manager.get(user__id__exact=self.id) …
self._profile_cache.user = self
except (ImportError, ImproperlyConfigured):
raise SiteProfileNotAvailable
return self._profile_cache
class Message(models.Model):
▼ Local vars
Variable Value
app_label
‘twitterauth’
model
None
model_name
‘UserProfile’
self
settings
[Reply]
I got past that bug with the help of the previous comments and answers. But then I ran into trouble when ‘twitter_return’ tried to save the UserProfile in the database. In filling in the query params deep down in the ORM code. The oauth.OAuthToken was being passed as the access token string. I think this change needs to be made in twitteroauth.py line 54 needs to have the to_string() function applied.
Original:
userprofile.access_token = access_token
Modified:
userprofile.access_token = access_token.to_string()
This is required because userprofile.access_token is a CharField.
[Reply]
So this works if the person is already logged into Twitter, at which point he can approve your app. What if the person is not logged in? Right now you get a 401 error. How can I have him login and then approve the app?
[Reply]
Joe Cascio Reply:
February 16th, 2010 at 12:57 pm
Twitter should direct you to its login page, thence to the authorization page.
[Reply]
Hello!
This example works great! Thank you for your post.
There is one consideration in your code: In twitter, you can change your username. So, if the user changes, the account must be “recreated” in django.
This is bad when you are storing local information. Is there a way to use a userID instead of username?
Best Regards,
Lucas.
[Reply]
Just a heads up — i had a similar error to Joe. It was apparently a conflict that arose from having the same superuser name and twitter account name. i made a new superuser, got rid of the old one and successfully logged in
[Reply]
I am having an issue with this implementation.
Any insight would be much appreciated
/usr/local/Python64_2.6/lib/python2.6/urllib2.py in http_error_default
The error occurs when I make this call.
access_token = twitter.getAccessToken()
Any idea what the issue is.
I am using this from a browser and this occurs int he callback_url handling.
Is the problem that I am not passing the pin, if so, how do I get at the pin in the callback_url.
Thanks very much,
-Mike
here is the tracebacks in case it’s helpful.
Traceback:
File “/usr/local/Python64_2.6/lib/python2.6/site-packages/django/core/handlers/base.py” in get_response
92. response = callback(request, *callback_args, **callback_kwargs)
File “/Users/mpresh/events/web/demo/../demo/twitterauth/views.py” in twitter_return
49. access_token = twitter.getAccessToken()
File “/usr/local/Python64_2.6/lib/python2.6/oauthtwitter.py” in getAccessToken
183. token = self._FetchUrl(url, no_cache=True)
File “/usr/local/Python64_2.6/lib/python2.6/oauthtwitter.py” in _FetchUrl
104. url_data = opener.open(url).read()
File “/usr/local/Python64_2.6/lib/python2.6/urllib2.py” in open
395. response = meth(req, response)
File “/usr/local/Python64_2.6/lib/python2.6/urllib2.py” in http_response
508. ‘http’, request, response, code, msg, hdrs)
File “/usr/local/Python64_2.6/lib/python2.6/urllib2.py” in error
433. return self._call_chain(*args)
File “/usr/local/Python64_2.6/lib/python2.6/urllib2.py” in _call_chain
367. result = func(*args)
File “/usr/local/Python64_2.6/lib/python2.6/urllib2.py” in http_error_default
516. raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
Exception Type: HTTPError at /return/
Exception Value:
[Reply]
I want to use twitter login button like facebook login button. So that I can just open a new window without redirecting page to twitter auth site.
[Reply]
Hi,
I am getting the following error in return function
‘module’ object has no attribute ‘OAuthToken’, but I have correctly configured oauth. Any ideas?
thanks
ashwin
[Reply]
Arnolds Reply:
September 7th, 2010 at 8:06 am
Ashwin – you should change
“import oauth”
to
“import oauth.oauth as oauth”
[Reply]
I am getting the following error when I goto http://localhost:8000/login.
May be it’s because I am not getting the
correct consumer key and secret key, as I have no website, still in development phase.
Please help
Traceback (most recent call last):
File “/usr/lib/pymodules/python2.6/django/core/servers/basehttp.py”, line 279, in run
self.result = application(self.environ, self.start_response)
File “/usr/lib/pymodules/python2.6/django/core/servers/basehttp.py”, line 651, in __call__
return self.application(environ, start_response)
File “/usr/lib/pymodules/python2.6/django/core/handlers/wsgi.py”, line 241, in __call__
response = self.get_response(request)
File “/usr/lib/pymodules/python2.6/django/core/handlers/base.py”, line 73, in get_response
response = middleware_method(request)
File “/usr/lib/pymodules/python2.6/django/middleware/common.py”, line 56, in process_request
if (not _is_valid_path(request.path_info) and
File “/usr/lib/pymodules/python2.6/django/middleware/common.py”, line 142, in _is_valid_path
urlresolvers.resolve(path)
File “/usr/lib/pymodules/python2.6/django/core/urlresolvers.py”, line 303, in resolve
return get_resolver(urlconf).resolve(path)
File “/usr/lib/pymodules/python2.6/django/core/urlresolvers.py”, line 216, in resolve
for pattern in self.url_patterns:
File “/usr/lib/pymodules/python2.6/django/core/urlresolvers.py”, line 245, in _get_url_patterns
patterns = getattr(self.urlconf_module, “urlpatterns”, self.urlconf_module)
File “/usr/lib/pymodules/python2.6/django/core/urlresolvers.py”, line 240, in _get_urlconf_module
self._urlconf_module = import_module(self.urlconf_name)
File “/usr/lib/pymodules/python2.6/django/utils/importlib.py”, line 35, in import_module
__import__(name)
File “/home/baharali/twitterapp/../twitterapp/urls.py”, line 7, in
url(‘^login/$’, twitter_signin, name=’login’),
NameError: name ‘twitter_signin’ is not defined
[Reply]
Hi,
great guide, thank you a lot! =)
I came across a more or less new Problem:
File “django/core/handlers/base.py”, line 100, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File “social/views.py”, line 123, in twitter_return
twitter = OAuthApi(CONSUMER_KEY, CONSUMER_SECRET, token)
File “social/oauthtwitter.py”, line 50, in __init__
Api.__init__(self,access_token.key, access_token.secret)
File “social/twitter.py”, line 1996, in __init__
raise TwitterError(‘Twitter requires oAuth Access Token for all API access’)
TwitterError: Twitter requires oAuth Access Token for all API access
Any idea anyone?
Someone also posted it on sstackoverflow already, but no answers yet…
http://stackoverflow.com/questions/4577143/show-error-twitter-requires-oauth-access-token-for-all-api-access
I also changed it to be independend from my normal UserProfile, so the django-app social contains login and acces to facebooks graph api, twitter and some other stuff, and can be added without requiring changes in any other app or model.
If someone’s interested, i can opensource it.
[Reply]
Hameedullah Khan Reply:
January 19th, 2011 at 10:35 am
Hey Drik,
I am sorry to hear that you people are facing trouble. Please allow me sometime so I can try everything myself, and create a working demo for you.
If you don’t hear from me in 2 days.. then you or anyone else please ping me, I will appreciate that.
[Reply]
I’m encountering the same problem as Dirk: “TwitterError: Twitter requires oAuth Access Token for all API access”
[Reply]
Markus Reply:
February 13th, 2011 at 12:49 am
Change this line:
Api.__init__(self,access_token.key, access_token.secret)
To:
Api.__init__(self,access_token_key=access_token.key, access_token_secret=access_token.secret)
[Reply]
Drik and Dysolution, I was haivng the same issue. I fixed it by changing the constructor for OAuthApi:
class OAuthApi(Api):
def __init__(self, consumer_key, consumer_secret, access_token=None):
if access_token:
Api.__init__(self,access_token.key, access_token.secret, settings.TWITTER_CONSUMER_KEY, settings.TWITTER_CONSUMER_SECRET)
else:
Api.__init__(self)
self._Consumer = oauth.OAuthConsumer(consumer_key, consumer_secret)
self._signature_method = oauth.OAuthSignatureMethod_HMAC_SHA1()
self._access_token = access_token
matt snider´s last blog post ..Web Development News January 2011 B
[Reply]
I’m using OAuth2 as oauth in appengine but it does not accept the OAuthToken, any suggestions on what I may need to change?
[Reply]
I followed this tutorial exactly and am getting these errors:
NameError at /
name ‘twitter_signin’ is not defined
I’ve tried variations on this multiple times, either something has changed in a django update and this code needs to be updated, or some other issue.
I’m brand new to django so to save the frustrations of others, I’d say skip this “guide”, because all you will have is problems.
[Reply]