Yuwen Yan
Yuwen Yan

Reputation: 4935

Passing token to the client

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

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?

Upvotes: 4

Views: 3491

Answers (3)

Rahul Gupta
Rahul Gupta

Reputation: 47906

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.

Upvotes: 1

Ben Burns
Ben Burns

Reputation: 15226

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

Upvotes: 2

mjpirez
mjpirez

Reputation: 7

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.

Upvotes: 0

Related Questions