Custom and Social Authentication for Mobile App Backend, using webapp2

79 views
Skip to first unread message

Clint Doriot

unread,
Apr 10, 2015, 2:56:40 PM4/10/15
to web...@googlegroups.com
I'm trying to set up a backend on GAE (python, webapp2) for my mobile game that allows for custom authentication as well as social integration. I've ready several threads, stack overflow questions and tutorials related to this, and each solves a small piece of the puzzle, but I haven't quite seen how to tie it all together.

The requirements I'm trying to hit:
  1. Allow for "anonymous" accounts - Basically, the player should be able to start playing the game immediately without signing up, but we still keep basic stats (number of games played, trophies won, high score, etc.). No personal information
  2. Allow for email/username based accounts - Basically the user can specify their own username or email, and a password. This has the primary advantage over 'anonymous' accounts in that the player can access the account from multiple devices.
  3. Allow for social based accounts - Authenticate through Facebook or Twitter so that players can create games against their friends.
  4. Allow users to sign in to multiple social accounts. The basic implication here is that we need the User model to be tied to a system user id, and not directly tied to their social ID. 

What I've done so far:

I've set up a webapp2 based system that allows for the anonymous accounts, following Alessandro Bahgat's tutorial. Its modified so that the user creation process generates a random system username, which is both the entity's key, and currently, their one listed auth ID. A long random character password is generated for them, its stored securely on the server to check against later, and is passed back to the client when the user is created. Its stored encrypted on the device, and passed back to the server to create a session when the app is opened or if the current session expires.

This should be easily extendable to handle email/username based accounts, where these are supplied by the app instead of being generated randomly.

I've also started on integrating Twitter authentication, using tweepy. The user authenticates within the app, and then passes the auth token and secret to the server (over https). I plan to store them encrypted in the datastore, so that I can retrieve them later in a task queue that fetches friends and followers, to create social links between users (for leaderboards, versus matches, etc.). I'll strip these out of the user data dictionary whenever I'm serving user data to the app.

Where I'm hung up:

First,
What would be the most google-app-engine-way of storing these additional credentials to ensure scalability and facilitate session authentication? Current options I've considered:
  • webapp2 has a built-in auth_ids list, and I'm currently storing my randomized user id in there. However, I haven't actually seen any examples that show authenticated against different auth IDs. I'm assuming with this approach, when the auth api call is made, we'd need to query for a user based on the selected auth id, and then do an authentication method appropriate for that type of auth ID (checking the password, checking the user token/secret against twitter's api, etc.)
  • Store the twitter ID as a custom field. The only reason this might be an option is if querying this way is faster than querying on the repeatable property. My guess is that it doesn't matter, but I'm not opposed to this approach, since we'll need custom fields for the auth token / secret anyways, and we're only ever going to integrate Twitter and Facebook.
  • Store the social auth information in a separate model. This is the approach that gae-boilerplate takes (I can't use that project as is, because its too heavily geared toward a web application and not mobile backend). Using this general approach, to authenticate and fetch user data, we'd directly get the social auth entity based on key (the auth id), then directly get the user entity based on key (which was stored in the social entity)
Are any of these approaches immediately clear as just plain bad practice? Which scales better- Looking up two entities, sequentially, by key, or doing a single query?


Second,
I'm not really sure where to integrate the social authorization check into the session creation process (login). For the custom authentication described in Bahgat's tutorial, this is done with a combination of the Auth class and the User model that's passed in through configuration, and with some function overrides. Namely, the login process passes the username and password to the Auth class, which then really just pass it to the user model. The user model compares the provided password against the securely stored password.

With social authentication, you're going to get the auth token (facebook) or auth token and secret (twitter). Where should I extend webapp2 to check these against their respective APIs, in order to maintain the rest of the session structure? Options I considered:
  • Forget passing it through the webapp2 auth class to the user model. Just fetch / query all the necessary entities and interface with the social APIs, directly in the login handler
  • Extend the auth class to add in a function for .get_user_by_social_auth(self, auth_id, auth_token, auth_secret), that mimics the auth.get_user_by_password(...). This function of course just transfers it to my custom user model which does the actual check against the stored data or social API
  • Package up the auth token and secret into a single string, and pass that through as the 'password' in the .get_user_by_password function. Override the user model's .get_user_by_password to handle the 'password' appropriately based on whether or not the provided auth id is the system id, facebook id, or twitter id.

Finally, just as a sanity check, if you see any glaring security holes that this whole approach causes, your feedback is appreciated! I'm no security expert, so I'm second-guessing myself with the anonymous accounts approach and the auth token / secret storage.

Thank you,

-Clint
Reply all
Reply to author
Forward
0 new messages