Social Login - Twitter logs out plus some other issues- web2py 2.8.2 / Mac OS X 10.9.1

214 views
Skip to first unread message

Luciano Laporta Podazza

unread,
Dec 22, 2013, 3:43:25 PM12/22/13
to web...@googlegroups.com
Hello,

I'm trying to implement Social Login following this example exactly as it shows here:


Facebook works well, but I'm having some issues:

1. Twitter login works fine, but when it returns from twitter's login page to my web2py app(through the callback url), it happens two things:
  1.1 My web2py app automatically redirects to 'logout' method, leaving me in the default/index page and "logging me out", even if twitter auth succeed.
  1.2 Twitter user's data(like name, id, etc) is not stored in DB(Facebook login did store it)

Notes: To login with Twitter I use the regular login url(default/user/login) which redirects me to twitter auth so I set the Callback URL to be the same url. 

2. I want to use Facebook/Twitter/Web2py auth simultaneously (and if possible merge all accounts through email address or username) but I can't figure it out how to set auth.settings.login_form dynamically. Currently i'm setting it in db.py and can't be overdiden it in the controller. In other words, I'm facing the same issue JungHyun Kim is experiencing.

3. I don't want to use Janrain.

Thanks a lot for your help, I've already tried with a lot of outdated examples and it's driving me nuts :P

Cheers.


Leonel Câmara

unread,
Dec 23, 2013, 6:02:16 AM12/23/13
to web...@googlegroups.com
I wouldn't bother, you shouldn't be using twitter login if you want to merge on email accounts as twitter does not provide you with the user's email.
  
So, you have conflicting requisites, you want to merge social logins based on email and you want to have twitter login.  
  
It's possible, you can always ask the user for his email, but if you're going to all that trouble just make him register.  
  
Clients need to be made aware that using twitter to login for websites is mostly stupid unless your website is actually based around interacting with twitter as most websites end up needing the user's email address anyway.

Luciano Laporta Podazza

unread,
Dec 23, 2013, 12:06:47 PM12/23/13
to web...@googlegroups.com
Thanks for the advice Leonel!,

You're totally right, I should change the workflow, for instance, register the user using web2py auth and then asking for Facebook/Twitter permissions to access their API.

On the other hand, I'm still having some issues if I change the workflow:
Web2py stores Facebook user's data only if I set auth.settings.login_form in db.py and I trigger /user/login. Otherwise it does not work as expected.

This is the code I'm currently using:
db.py:


auth_table
= db.define_table(
    auth
.settings.table_user_name,
Field('name', length=128, default=""),
Field('first_name', length=128, default=""),
Field('last_name', length=128, default=""),
Field('username', length=128, default="", unique=True),
Field('password', 'password', length=256, readable=False, label='Password'),
Field('registration_id', length=128, default= "", writable=False, readable=False),
Field('registration_key', length=128, default= "", writable=False, readable=False))


auth_table
.username.requires = IS_NOT_IN_DB(db, auth_table.username)
auth
.define_tables(username=False, signature=False)


## configure email
mail
= auth.settings.mailer
mail
.settings.server = 'logging' or 'smtp.gmail.com:587'
mail
.settings.sender = 'you@gmail.com'
mail
.settings.login = 'username:password'


## configure auth policy
auth
.settings.registration_requires_verification = False
auth
.settings.registration_requires_approval = False
auth
.settings.reset_password_requires_verification = True


## Define oauth application id and secret.
FB_CLIENT_ID
='my_id'
FB_CLIENT_SECRET
="my_secret"


# import required modules
try:
   
import json
except ImportError:
   
from gluon.contrib import simplejson as json
from facebook import GraphAPI, GraphAPIError
from gluon.contrib.login_methods.oauth20_account import OAuthAccount




## extend the OAUthAccount class
class FaceBookAccount(OAuthAccount):
   
"""OAuth impl for FaceBook"""
    AUTH_URL
="https://graph.facebook.com/oauth/authorize"
    TOKEN_URL
="https://graph.facebook.com/oauth/access_token"


   
def __init__(self):
       
OAuthAccount.__init__(self, None, FB_CLIENT_ID, FB_CLIENT_SECRET,
                             
self.AUTH_URL, self.TOKEN_URL,
                              scope
='email,user_about_me,user_activities, user_birthday, user_education_history, user_groups, user_hometown, user_interests, user_likes, user_location, user_relationships, user_relationship_details, user_religion_politics, user_subscriptions, user_work_history, user_photos, user_status, user_videos, publish_actions, friends_hometown, friends_location,friends_photos',
                              state
="auth_provider=facebook",
                              display
='popup')
       
self.graph = None


   
def get_user(self):
       
'''Returns the user using the Graph API.
        '''

       
if not self.accessToken():
           
return None


       
if not self.graph:
           
self.graph = GraphAPI((self.accessToken()))


        user
= None
       
try:
            user
= self.graph.get_object("me")
       
except GraphAPIError, e:
            session
.token = None
           
self.graph = None


       
if user:
           
if not user.has_key('username'):
                username
= user['id']
           
else:
                username
= user['username']
               
           
if not user.has_key('email'):
                email
= '%s.fakemail' %(user['id'])
           
else:
                email
= user['email']    


           
return dict(first_name = user['first_name'],
                        last_name
= user['last_name'],
                        username
= username,
                        email
= '%s' %(email) )


# auth.settings.login_form=FaceBookAccount()
crud
.settings.auth = None


import oauth2 as oauth
from gluon.contrib.login_methods.oauth10a_account import OAuthAccount as OAuthAccount10a


consumer_key
= "my_key"
consumer_secret
=  "my_secret"


class TwitterAccount(OAuthAccount10a):
    AUTH_URL
= "http://twitter.com/oauth/authorize"
    TOKEN_URL
= "https://twitter.com/oauth/request_token"
    ACCESS_TOKEN_URL
= "http://twitter.com/oauth/access_token"
   
def __init__(self, g=globals()):
       
OAuthAccount10a.__init__(self, g,
                              consumer_key
,
                              consumer_secret
,
                             
self.AUTH_URL,
                             
self.TOKEN_URL,
                             
self.ACCESS_TOKEN_URL)
                             
   
def get_user(self):        
       
if self.accessToken() is not None:            
            client
= oauth.Client(self.consumer, self.accessToken())
            resp
, content = client.request('http://api.twitter.com/1.1/account/verify_credentials.json')
           
if resp['status'] != '200':
               
# cannot get user info. should check status
               
return None
            u
= json.loads(content)            
           
return dict(username=u['screen_name'], name=u['name'], registration_id=str(u['id']))


controller.py:
def twitter():
    auth
.settings.login_form=TwitterAccount()
   
return dict(form=auth())


def facebook():
    auth
.settings.login_form=FaceBookAccount()
   
return dict(form=auth())


So the idea is to call myapp/default/twitter or myapp/default/facebook to get some user data and store it in DB but when it gets facebook/twitter authorization then I get redirected to /user/login and nothing happens.

I've been reading the manuals, outdated examples, etc; and can't find a good hint about what to do.

Any help will be appreciated.

Thanks.

Tito Garrido

unread,
Feb 17, 2014, 5:07:35 PM2/17/14
to web...@googlegroups.com
Hi Luciano,

Did you find a way to use auth.settings.login_form in the controllers? I am facing the same issue.

Regards,

Tito


--
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
---
You received this message because you are subscribed to the Google Groups "web2py-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to web2py+un...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



--

Linux User #387870
.........____
.... _/_õ|__|
..º[ .-.___.-._| . . . .
.__( o)__( o).:_______

Luciano Laporta Podazza

unread,
Feb 17, 2014, 11:23:25 PM2/17/14
to web...@googlegroups.com
Hi Tito,

Actually yes but I forgot to tell you guys :P

I don't know if it's the best, compliant way of doing it but it works for me. I just ended up using flags taking advantage of  'session' and under the db.py. For instance:

db.py:
if session.facebook == 1:
    auth.settings.login_form = FaceBookAccount()
elif session.facebook == 0:
    pass

controller.py:
def index():
    session.facebook = 0

def facebook():
    session.facebook = 1
    return dict(form=auth())


And that's all, whenever the user hits myapp/default/facebook it will redirect the user to facebook auth, login, and register it leaving the regular login/register intact and totally functional :)

Hope it makes sense and that it helps you.

Cheers



You received this message because you are subscribed to a topic in the Google Groups "web2py-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/web2py/Dx7Aq67y8VI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to web2py+un...@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.



--
Atte
Luciano Laporta Podazza
Reply all
Reply to author
Forward
0 new messages