title: How to exchange Google one-time authorization code for a refresh token without callback (intranet)?
body: <p>I'm working on a intranet-based application and I want to use Google services. Currently I have successfully implemented Google Authentication with "Sign-In for Websites" using JavaScript client-side authentication. My users can now sign in or sign up with their Google accounts.</p>
  
  <p>Now I want to use Google API to create and share Google Sheets with my users. These documents will be created with a specific Google account and then shared with my users.</p>
  
  <p>This is why I want to use this server-slide flow to get a one-time authorization code and exchange it for a refresh token:
  <a href="https://developers.google.com/identity/sign-in/web/server-side-flow" rel="noreferrer">https://developers.google.com/identity/sign-in/web/server-side-flow</a></p>
  
  <p><a href="https://i.stack.imgur.com/kbQA4.png" rel="noreferrer"><img src="https://i.stack.imgur.com/kbQA4.png" alt="Google hybrid Server-side flow"></a></p>
  
  <p>This refresh token will be stored in my database allowing me to user Google services on behalf of this offline user.</p>
  
  <p>Using JavaScript library, <strong>I was able to get the one-time authorization code that I send to my server with a AJAX request.</strong></p>
  
  <pre><code>auth2.grantOfflineAccess({'redirect_uri': 'postmessage'}).then(grantOfflineAccessCallback);
  
  var grantOfflineAccessCallback = function(authResult) {
      var auth_code = authResult.code;
  
      // Exchange the one-time authorization code for tokens
      $.post(...);
  }
  </code></pre>
  
  <p>On server-side I use Google API PHP Client (v2.0.0-RC6) to acquire an access and refresh token.</p>
  
  <pre><code>$this-&gt;client = new Google_Client();
  $this-&gt;client-&gt;setClientId($this-&gt;clientId);
  $this-&gt;client-&gt;setClientSecret($this-&gt;clientSecret);
  $this-&gt;client-&gt;setAccessType('offline');
  $this-&gt;client-&gt;setApprovalPrompt('force');
  
  $response = $this-&gt;client-&gt;fetchAccessTokenWithAuthCode($oneTimeCode);
  </code></pre>
  
  <p><strong>I wasn't able to exchange the authorization code.</strong></p>
  
  <pre><code>Client error: `POST https://www.googleapis.com/oauth2/v4/token` resulted in a `400 Bad Request` response:
  {
   "error": "invalid_request",
   "error_description": "Missing parameter: redirect_uri"
  }
  </code></pre>
  
  <p>On this page we can read:</p>
  
  <blockquote>
    <p>On the server, exchange the auth code for access and refresh tokens.
    Use the access token to call Google APIs on behalf of the user.</p>
  </blockquote>
  
  <p>On the JAVA example code:</p>
  
  <pre><code>REDIRECT_URI: // Specify the same redirect URI that you use with your web
                // app. If you don't have a web version of your app, you can
                // specify an empty string.
  </code></pre>
  
  <p>Because the application I working on is an intranet application, I tried to specify an empty string for this redirect_uri parameter before calling fetchAccessTokenWithAuthCode() method:</p>
  
  <pre><code>$this-&gt;client-&gt;setRedirectUri('');
  </code></pre>
  
  <p>... result in <code>Redirect URI must be absolute</code>.</p>
  
  <p><strong>Can we use this hybrid server-slide flow without callback URL?</strong></p>
  
  <p>Is there any solution to my problem?</p>
  
  <p>Thanks,</p>
  
  <hr>
  
  <h2>Edit:</h2>
  
  <p>redirect_uri is where the user will be redirected to after he signed in. This URL must be registered in the Google Project (developers console). <strong>So redirect_uri is NOT the callback...!</strong></p>
  
  <p>Problem is now solved with:</p>
  
  <pre><code>$this-&gt;client-&gt;setRedirectUri('http://same.url.as.in.developers.console/');
  </code></pre>