title: Django 1.7 google oauth2 token validation failure
body: <p>I'm trying to get through the process of authenticating a Google token for accessing a user's calendar within a Django application. Although I've followed several indications found on the web, I'm stuck with a 400 error code response to my callback function (Bad Request).</p>
  
  <p><strong>views.py</strong></p>
  
  <pre><code># -*- coding: utf-8 -*-
  import os
  
  import argparse
  import httplib2
  import logging
  
  from apiclient.discovery import build
  from oauth2client import tools
  from oauth2client.django_orm import Storage
  from oauth2client import xsrfutil
  from oauth2client.client import flow_from_clientsecrets
  
  from django.http import HttpResponse
  from django.http import HttpResponseBadRequest
  from django.http import HttpResponseRedirect
  from django.shortcuts import render_to_response
  from django.core.urlresolvers import reverse
  from django.contrib import auth
  from django.contrib.auth.decorators import login_required
  from django.conf import settings
  
  from apps.tecnico.models import Credentials, Flow
  
  CLIENT_SECRETS = os.path.join(
      os.path.dirname(__file__), '../../client_secrets.json')
  
  @login_required
  def index(request):
      storage = Storage(Credentials, 'id', request.user, 'credential')
      FLOW = flow_from_clientsecrets(
          CLIENT_SECRETS,
          scope='https://www.googleapis.com/auth/calendar.readonly',
          redirect_uri='http://MY_URL:8000/oauth2/oauth2callback'
      )
      credential = storage.get()
      if credential is None or credential.invalid is True:
          FLOW.params['state'] = xsrfutil.generate_token(
              settings.SECRET_KEY, request.user)
          authorize_url = FLOW.step1_get_authorize_url()
          f = Flow(id=request.user, flow=FLOW)
          f.save()
          return HttpResponseRedirect(authorize_url)
      else:
          http = httplib2.Http()
          http = credential.authorize(http)
          service = build(serviceName='calendar', version='v3', http=http,
                          developerKey='MY_DEV_KEY_FROM_GOOGLE_CONSOLE')
  
          events = service.events().list(calendarId='primary').execute()
          return render_to_response('calendario/welcome.html', {
              'events': events['items'],
          })
  
  
  @login_required
  def auth_return(request):
      if not xsrfutil.validate_token(
              settings.SECRET_KEY, request.REQUEST['state'], request.user):
          return HttpResponseBadRequest()
  
      storage = Storage(Credentials, 'id', request.user, 'credential')
      FLOW = Flow.objects.get(id=request.user).flow
      credential = FLOW.step2_exchange(request.REQUEST)
      storage.put(credential)
      return HttpResponseRedirect("http://MY_URL:8000/caly")
  </code></pre>
  
  <p><strong>models.py</strong></p>
  
  <pre><code>from oauth2client.django_orm import FlowField, CredentialsField
  
  [...]
  
  class Credentials(models.Model):
      id = models.ForeignKey(User, primary_key=True)
      credential = CredentialsField()
  
  
  class Flow(models.Model):
      id = models.ForeignKey(User, primary_key=True)
      flow = FlowField()
  </code></pre>
  
  <p>I've downloaded the <em>client_secrets.json</em> file directly from the Google Dev Console.
  The specified Client ID type in the Dev Console is "web application", which I think is correct.
  What I've noticed is, if I remove the token validation code block:</p>
  
  <pre><code>if not xsrfutil.validate_token(
          settings.SECRET_KEY, request.REQUEST['state'], request.user):
      return HttpResponseBadRequest()
  </code></pre>
  
  <p>everything works correctly, flow and credentials get correctly stored in the database and I'm allowed to read the calendar. What can I possibly be wrong with?</p>
  
  <p><strong>EDIT</strong>: I've also checked outgoing (to Google) and incoming (to callback) data:</p>
  
  <p><strong>OUTGOING</strong>:</p>
  
  <pre><code>request.user:
  admin
  settings.SECRET_KEY:
  I_AM_NOT_WRITING_IT_HERE
  FLOW.params['state']:
  SOME_OTHER_RANDOM_STUFF
  </code></pre>
  
  <p><strong>INCOMING</strong>:</p>
  
  <pre><code>request.user:
  admin
  settings.SECRET_KEY:
  I_AM_NOT_WRITING_IT_HERE
  FLOW.params['state']:
  SOME_OTHER_RANDOM_STUFF
  </code></pre>
  
  <p>Data is identical, at least to a <em>print</em> to console. Also, the generation/validation operations via console work correctly (xsrfutil.validate_token returns True, both with test and real data, including User model instances). I'm even more puzzled.</p>