1

I want to allow registered users to add multiple twitter accounts. I followed twython-django example, and got a working version of one user - one twitter account. If the user tries to use twitter login again, follows same view again, I get this error: Invalid / expired Token.

I tried adding force_login=true to oauth/authorize and oauth/authenticate, removing 'request_token' from request.session dict, but i still get Invalid Token error during get_authentication_tokens().

How to properly associate multiple twitter accounts with the same user, using twython? What am I missing here?

Here is an a twython-django example: https://github.com/ryanmcgrath/twython-django/blob/master/twython_django_oauth/views.py

My view:

def twitter_login(request):
    redirect_back_to_url = request.build_absolute_uri()

    if 'request_token' not in request.session:
        # request authorization tokens
        t = Twython(twitter_token=settings.TWITTER_CONSUMER_KEY,
                    twitter_secret=settings.TWITTER_CONSUMER_SECRET,
                    callback_url=redirect_back_to_url)

        # Request an authorization url to send the user to...
        request_oauth_key = t.get_authentication_tokens()

        # signing current session as one with twitter authentication
        request.session['request_token'] = request_oauth_key

        # redirecting the user to twitter authorization url for authentication
        return HttpResponseRedirect(request_oauth_key['auth_url'])
    else:
        # user authenticated, receiving auth token
        t2 = Twython(twitter_token=settings.TWITTER_CONSUMER_KEY,
                     twitter_secret=settings.TWITTER_CONSUMER_SECRET,
                     oauth_token=request.session['request_token'][
                         'oauth_token'],
                     oauth_token_secret=request.session['request_token'][
                         'oauth_token_secret'])

        oauth_key = t2.get_authorized_tokens()

        # save authorized tokens
        # twitter oauth tokens dont expire
        token = Token.objects.get_or_create(account_name=oauth_key['screen_name'],
                                            token=oauth_key['oauth_token'],
                                            secret=oauth_key['oauth_token_secret'])
        user = request.user.get_profile()
        user.twitter.add(token[0].id)
        user.save()

        logger.info('Successfully acquired twitter oauth token.')

        return HttpResponseRedirect(reverse('profile'))

Update: possible solution

I changed my view to this:

def twitter_login(request):
    redirect_back_to_url = request.build_absolute_uri()

    if 'request_token' not in request.session:
        # request authorization tokens
        t = Twython(twitter_token=settings.TWITTER_CONSUMER_KEY,
                    twitter_secret=settings.TWITTER_CONSUMER_SECRET,
                    callback_url=redirect_back_to_url)

        # Request an authorization url to send the user to...
        request_oauth_key = t.get_authentication_tokens()

        # signing current session as one with twitter authentication
        request.session['request_token'] = request_oauth_key

        # redirecting the user to twitter authorization url for authentication
        return HttpResponseRedirect(request_oauth_key['auth_url'])
    else:
        # user authenticated, receiving auth token
        t2 = Twython(twitter_token=settings.TWITTER_CONSUMER_KEY,
                     twitter_secret=settings.TWITTER_CONSUMER_SECRET,
                     oauth_token=request.session['request_token'][
                         'oauth_token'],
                     oauth_token_secret=request.session['request_token'][
                         'oauth_token_secret'])

        oauth_key = t2.get_authorized_tokens()
        if 'screen_name' not in oauth_key:
            del request.session['request_token']
            request.session.modified = True
            return HttpResponseRedirect(reverse('twitter_login'))

        # save authorized tokens
        # twitter oauth tokens dont expire
        token = Token.objects.get_or_create(account_name=oauth_key['screen_name'],
                                            token=oauth_key['oauth_token'],
                                            secret=oauth_key['oauth_token_secret'])
        user = request.user.get_profile()
        user.twitter.add(token[0].id)
        user.save()

        logger.info('Successfully acquired twitter oauth token.')

        return HttpResponseRedirect(reverse('profile'))

And not sure yet if this had anything to do with it. I added after line 272 in twython.py request_args['force_login'] = True. But, as i said, i'm not sure if that had any impact, cos according to https://dev.twitter.com/docs/api/1/post/oauth/request_token force login is not one of the optional args.

Some voodoo this was. lol. Tell me if its a total rubbish.

Neara
  • 3,693
  • 7
  • 29
  • 40
  • In my User i have twitter as M2M field. The problem is a user case like this: a user just signed in, and wants to add all his accounts. First one works ok and he sees his account was added. He tried to go through the same process again: twitter login with different credentials. In twitter login view, the request goes straight to get_authorized_tokens method, and it returns invalid token error. The problem is not in my model and how i save it, but in how to make twitter show login dialog again. – Neara Mar 20 '13 at 14:03
  • i went to all this pain to allow seamless post to multiple accounts. I stored proper token+secret pairs, as you can see in my code. With one token it worked ok. I didn't update yet the task that will post to twitter accounts. I think instantiating Twython with appropriate tokens should do the trick, no? – Neara Mar 20 '13 at 15:26
  • your codes are ok, the problem is you use again the token which result to Invalid / expired Token. So you must logout to accept other login account. I forgot why but it expires after you use it. – catherine Mar 20 '13 at 15:40
  • When I create facebook, twitter, and google login/registration I didn't find it difficult. I carefully read the codes then test. If successful I modified it so that I can associate multiple accounts. The original codes are from in different blogs then combined it :) – catherine Mar 20 '13 at 15:46
  • Can you post a code sample? – Neara Mar 21 '13 at 07:33
  • Or direct me to those blogs? I don't have problems with one social account per user. Twitter for example doesn't support logout, and end/session is no longer there either. – Neara Mar 21 '13 at 07:34

1 Answers1

1

Mmm, I believe OP got it working/right, but just as a quick breakdown, twython-django isn't built to support multiple account associations (it's also not on Django 1.5, so be careful with that until it's updated~).

You'd need to do what OP did and set up a separate table for Tokens that match over to a User, and then handle which account they're currently using by pulling the appropriate tokens. OPs use of force_login also seems to have worked because, while it's not necessarily documented, I believe it still works (according to this thread, unless I'm misreading it - if I am, I would love to be corrected).

I don't expect this answer to be accepted as I'm not really solving anything, but if anyone else encounters this I'm hoping to leave something more clear-cut than the above notes. Hope that's alright!

Ryan McGrath
  • 2,042
  • 14
  • 23
  • I do something similar, except without Django; I have a bunch of little scripts for specific purposes. Every time I create a new account and/or app auth tokens I just copy my scripts from the dev directory into a new "live" one, update the authinfo.py file (which has the keys and secret data to be imported) and away we go. – Ben Sep 29 '13 at 22:25