title: Making an AJAX request to a Django view that may require a redirect?
body: <p><strong>Introduction</strong></p>
  
  <p>I am getting an error when trying to request a particular Django view from AJAX. This view redirects the user if they have not yet authorized the site with Google. I believe that the problem lies in the fact that I am trying to perform the redirect from "within" a view requested by AJAX. Read on for more information, and thanks in advance for your help!</p>
  
  <p><strong>Background information</strong></p>
  
  <p>I wrote a view in Django called <code>export_to_drive</code> that uses the Google Drive API and returns some JSON.</p>
  
  <pre><code>@gauth_required(scope='https://www.googleapis.com/auth/drive.file')
  def export_to_drive(request, credential, sheet_id):
      """
      Export a sheet to Google Drive.
      """
      http = credential.authorize(httplib2.Http())
      service = build('drive', 'v3', http=http)
  
      # ...
  
      new_file = service.files().create(body=file_metadata,
                                        media_body=media,
                                        fields='webViewLink').execute()
  
      return jsonResponse(new_file)
  </code></pre>
  
  <p>This view requires the user to give the site permission to add files to their Google Drive on their behalf. In order to ensure that the user has authorized the site with Google, I wrote a decorator called <code>gauth_required</code>.</p>
  
  <pre><code>def gauth_required(scope):
      """
      Decorator that requires the user to authenticate
      with Google and authorize the site to act on their behalf.
      If the user has already authenticated, it will call the wrapped function
      with the kwarg `credential` set to the obtained credentials.
      If not, it will start the OAuth 2.0 flow.
      At the moment, only used for sheets.views.export_to_drive.
      """
      def wrapper(func):
          @login_required
          @wraps(func)
          def inner(request, *args, **kwargs):
              storage = Storage(CredentialsModel, 'id',
                                request.user, 'credential')
              credential = storage.get()
  
              if credential is None or credential.invalid:
                  request.session['next_view'] = request.path
                  return HttpResponseRedirect('/gauth?scope={}'.format(scope))
  
              kwargs['credential'] = credential
              return func(request, *args, **kwargs)
          return inner
      return wrapper
  </code></pre>
  
  <p>As you can (hopefully) see, this decorator checks to see if there is a stored credential object for the given user and if not, it will start the OAuth 2.0 authentication flow to obtain one. As I do not believe it is relevant to the question (and in an effort to refrain from scaring away potential answerers with enormous amounts of code), I'm choosing to not show you the code for the flow. The only real important detail to know about the it is that it requires several redirects (this will come up later).</p>
  
  <p><strong>The problem</strong></p>
  
  <p>The <code>export_to_drive</code> view is being accessed via a jQuery AJAX call from some client-side Javascript.</p>
  
  <pre><code>function exportToDrive() {
      $.post("/api/sheets/" + sjs.current.id + "/export_to_drive", function(data) {
          if ("error" in data) {
              sjs.alert.message(data.error.message);
          } else {
              sjs.alert.message("Source Sheet exported to Google Drive.&lt;br&gt;&lt;br&gt;&lt;a href='" + data.webViewLink + "'&gt;Open in Google Drive &amp;raquo;&lt;/a&gt;");
          }
      })
  }
  </code></pre>
  
  <p>When I attempt to click on the UI element that this function is bound to, I get the following error in the console if there is no credential on-file for the signed in user.</p>
  
  <pre><code>XMLHttpRequest cannot load https://accounts.google.com/o/oauth2/auth?state=zdsChtkBh_T7IoSyl5cpVDoxNDY…e=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.file&amp;access_type=offline. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access.
  </code></pre>
  
  <p>When I go directly to the <code>export_to_drive</code> endpoint in my browser, everything works dandy, regardless of whether the credential is retrieved from storage or created by the OAuth 2.0 flow. Therefore, I have a hunch that the problem lies in needing to perform a redirect to complete the authorization flow from within an AJAX request.</p>
  
  <p><strong>The question(s)</strong></p>
  
  <ul>
  <li>Is it possible to perform a redirect from a requested AJAX url? If not, is there a good way to refactor this code to make it work without needing to do that?</li>
  <li>Has anyone dealt with this or something similar to this before?</li>
  <li>Is my suspicion completely off-base and something else entirely is causing this error?</li>
  </ul>