4

I'm developing an iOS app and using Django for backend. There are two apps I'm using in Django

  • Django OAuth Toolkit to support OAuth authentication
  • Python Social Auth to support social authentication

The social authentication process should be:

  1. GET localhost/login/{application}
  2. Authentication on Application site
  3. Redirect to localhost/complete/{application}
  4. Fetch {application}'s access token
  5. Create a new user with my server's access token, and associate it with {application}'s access token
  6. Redirect to localhost/accounts/profile

Then, I can use my server's access token to communicate with {application}.

But the client will see that the browser start with localhost/login/{application} and end with localhost/accounts/profile, and still don't know what is my server's access token, so my question is how to pass the access token to the client?

One solution is that redirect with access token as localhost/accounts/profile?token=MyServerToken, but how to add parameter when redirecting to profile url?

Yuwen Yan
  • 4,777
  • 10
  • 33
  • 63
  • What does client intend to do with the server's access token? – Rahul Gupta Sep 08 '15 at 15:27
  • 1
    I'll use the server's access token to request data, if the data is on {application}, my server will use {application}'s access token to request data, and back to the client. – Yuwen Yan Sep 08 '15 at 15:36

3 Answers3

2

You likely already have what you need on the Django session for your user in question. That is, provided you are using the session middleware (auth of this type is nearly impossible without it), your identity provider specific tokens will usually be populated in the extra_data dict on the SocialUser model for the specific provider in question.

For example, assuming you have a reference to the Django user model (lets call it user):

access_token = user.social_auth.get(provider='google-oauth2').extra_data['access_token']

Unfortunately the specifics will vary depending on the backend you're working with. Remember that these tools are designed to let users authenticate against your app rather than to let you perform arbitrary actions against the product-specific APIs exposed by the various identity providers.

As for passing these tokens to the client, I'd need to know more about your use case. Chances are the identity provider in question set some session cookies on the client during its authentication flow. For example, if you sign in with Facebook, they set a few cookies which are automatically retrieved by the Facebook client-side javascript API. As such, there's no explicit sharing of tokens necessary between the server and the client.

Otherwise, if you must do it yourself, store them on a secure session cookie as follows:

response.set_cookie(social_auth_tokens,
    value=your_data_here,
    max_age=None, #cookie will expire at end of user session
    expires=None,
    path='/',
    domain=None, #only readable by this domain
    secure=True, #only transmitted over https
    httponly=False) #readable by scripts running on the page
Ben Burns
  • 14,978
  • 4
  • 35
  • 56
1

You should not pass the access token in the query string like /?token=my_token. Its not a secure way and definitely not recommended.

Some other approaches you can use are:

Approach-1: Setting server_access_token in response headers

You can set the access token in the response headers and send it using HTTPS protocol.

The token will be sent once and consumed by the client. Since the response headers are not passed in the subsequent requests, the token will be passed only once to the client. Client will then use it to make further requests by setting the token in the request headers.

class MySocialApplicationRedirectView(View):

    def get(self, request, *args, **kwargs):  
        # Here, write your code to fetch the  {application}'s access token, 
        # creating a new user with your server's access token, and then
        # associating it with {application}'s access token

        # assign the response to a variable and set the access token as a header in the response 
        response = HttpResponseRedirect('/accounts/profile/')       
        response['X-Auth-Token'] = 'my_server_access_token'    

        # can also use the below name as 'X-' prefixed headers are deprecated     
        # response['Auth-Token'] = 'my_server_access_token'

        return response 

Client can then retrieve the token from the headers and use this token to make further requests. In further requests, he must send the access token in request headers.

Approach-2: Setting server_access_token as a cookie

Another option is to set the server_access_token cookie in your response as @Ben mentioned.

response.set_cookie() would set the server_access_token cookie in the response and then the client can read the cookie and send this in further requests in the request headers.

class MySocialApplicationRedirectView(View):

        def get(self, request, *args, **kwargs):  
            # Here, write your code to fetch the  {application}'s access token, 
            # creating a new user with your server's access token, and then
            # associating it with {application}'s access token

            # assign the response to a variable and set the access token as a cookie in the response object
            response = HttpResponseRedirect('/accounts/profile/')       
            response.set_cookie(key, value='my_server_access_token', ..other parameters )
            return response 

Note: For safety and security, all requests (both to obtain and use the tokens) must use HTTPS endpoints.

Community
  • 1
  • 1
Rahul Gupta
  • 46,769
  • 10
  • 112
  • 126
  • Thanks for your answer, do you mean that I need to change the code of `Python Social Auth` directly? – Yuwen Yan Sep 15 '15 at 11:07
  • This duplicates other more standards-compliant functionality. Session cookies were created for this exact purpose and they are likely already supported by the client code without the need for any special handling, as the session itself is managed by the backend. – Ben Burns Sep 15 '15 at 11:45
  • @ybbaigo You will have to do that when you are doing points 4,5,6 of your question. At the time of redirection to `localhost/accounts/profile`, you can set the headers.`MySocialApplicationRedirectView` is the view where the social application will redirect to the url to which your server is listening. – Rahul Gupta Sep 15 '15 at 17:05
  • @BenBurns agreed and updated the ans. The intention was to send the token in the response headers where the client would consume the token. The response headers aren't passed in subsequent requests. So, the token would be sent once and consumed. I had avoided setting the token in cookie as then the token would be sent in the request headers as well as the request cookies. – Rahul Gupta Sep 15 '15 at 17:22
  • 1
    No worries - removed my downvote. Also you might want to note that non-standard headers are typically prefixed by `X`, and generally hyphens are used in header keys instead of underscores, so to keep with typical conventions you likely want to set `X-Auth-Token` if you're using headers. In fact, if you google around a bit you'll see that this header key is used by a number of frameworks that do header-based auth. – Ben Burns Sep 15 '15 at 21:17
  • @BenBurns Yes, Thanks for pointing that out. I have modified my ans slightly. Also, i would like to mention that even though its being followed quite often, this convention was deprecated in June 2012 because of the inconveniences it caused when non-standard fields became standard. Check this RFC draft [RFC 6648](https://tools.ietf.org/html/rfc6648) and this [SO link](http://stackoverflow.com/questions/3561381/custom-http-headers-naming-conventions) – Rahul Gupta Sep 16 '15 at 03:14
0

It does not answer your specific question, but I've solved similar problem using TastyPie. It was very straightforward, didn't have to handle more than one application though, but since it provides an API for any given application, shouldn't be a problem.

mjpirez
  • 7
  • 1