Search code examples
pythondjangooauth-2.0foursquaredjango-authentication

Django + Foursquare OAuth + User Login


I've looked at some other questions on this topic around google and stackoverflow but can't seem to find the right solution. I am trying to authenticate user for an application using foursquare. When a user logs in with foursquare, I want to create then as a user in the database and store some of their information. This all works fine. At the same time, I want to log them in as an authenticated user. This is where I'm having some trouble. My view looks like this:

def foursq_done(request):
# get the access_token
access_token = request.session.get('access_token')
print access_token

# request user details from foursquare
params = {'oauth_token': access_token}
data = urllib.urlencode(params)
url = 'https://api.foursquare.com/v2/users/self'
full_url = url + '?' + data
print full_url
response = urllib2.urlopen(full_url)
response = response.read()
user_data = json.loads(response)['response']['user']
name = user_data['firstName']

try:
    user = User.objects.get(username=user_data['contact']['email'])
except User.DoesNotExist:
    # Save information on user
    user = User.objects.create_user(username=user_data['contact']['email'],
        first_name=user_data['firstName'], last_name=user_data['lastName'],
        email=user_data['contact']['email'], password=access_token)
    profile = Profile()
    profile.user = user
    profile.oauth_token = access_token
    profile.save()

user = authenticate(username=user_data['contact']['email'], password=access_token)

login(request, user)

# show the page with the user's name to show they've logged in
return TemplateResponse(request, 'foursq_auth/foursq_welcome.html', {'name': name}

This is the same login process I have used when creating a Django user before, like in this view:

def user_signup(request):
if request.method == 'POST':
    form = forms.UserSignupForm(data=request.POST)
    if form.is_valid():
        user = form.save()
        g = Group.objects.get(name='test_group')
        g.user_set.add(user)
        # log user in
        username = form.cleaned_data['username']
        password = form.cleaned_data['password1']
        user = authenticate(username=username, password=password)
        login(request, user)
        messages.success(request, u'Welcome to Social FollowUp')
        return redirect('user_create')
else:
    form = forms.UserSignupForm()
return TemplateResponse(request, 'user_signup.html', {
    'form': form,
})

I want the same result with my foursquare login process -- the user is authenticated and logged in/recognized as a Django user. Instead I keep seeing this error:

Internal Server Error: /tattoo/foursquare/done/
Traceback (most recent call last):
File "/Users/triplec1988/projects/tattoo/venv/lib/python2.7/site-       packages/django/core/handlers/base.py", line 115, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
File "/Users/triplec1988/projects/tattoo/tatt2me/web_tatt2me/views.py", line 106, in foursq_done
login(request, user)
File "/Users/triplec1988/projects/tattoo/venv/lib/python2.7/site-packages/django/contrib/auth/__init__.py", line 92, in login
request.session[BACKEND_SESSION_KEY] = user.backend
File "/Users/triplec1988/projects/tattoo/venv/lib/python2.7/site-packages/django/utils/functional.py", line 203, in inner
return func(self._wrapped, *args)
AttributeError: 'AnonymousUser' object has no attribute 'backend'

I don't want the foursquare user to be an AnonymousUser, but clearly something is not working when I run authenticate(). What am I doing wrong?


Solution

  • Right now it's only checking the standard Django backend but you have to write a custom one that takes a user authenticated via OAuth from foursquare and authenticates them via the Django user auth model.

    In settings.py

    AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',
                               'YOUR_APP.backends.FoursquareBackend',)
    

    backends.py

    from django.contrib.auth.models import User
    from django.contrib.auth.backends import ModelBackend
    
    
    class FoursquareBackend(ModelBackend):
        def authenticate(self, username=None, password=None):
            try:
                user = User.objects.get(username=username)
                return user
            except User.DoesNotExist:
                print "Looks like this user does not exist"
            return None
    
        def get_user(self, user_id):
            try:
                return User.objects.get(pk=user_id)
            except User.DoesNotExist:
                return None