title: Google Identity Toolkit API in C#
body: <h2>Some Background Information</h2>
  
  <p>I am building a game in Unity, using C#. Since I am using Firebase and the ready-made Unity Firebase SDK won't work in my case<sup>1</sup>, I have resorted to interfacing with <a href="https://firebase.google.com/docs/reference/rest/auth#section-refresh-token" rel="nofollow noreferrer">Firebase's REST API</a> through C#'s <a href="https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=netframework-4.8" rel="nofollow noreferrer"><code>HttpClient</code></a> class (which comes with <code>System.Net.Http</code>).</p>
  
  <p>I am currently struggling with the Firebase Authentication APIs. For those unfamiliar with OAuth APIs, when I call the Sign Up or Sign In endpoints, I get both an <em>ID Token</em> and a <em>Refresh Token</em>. ID Tokens expire; refresh tokens do not. When the ID Token expires, I must call another endpoint, called the <em>Token Exchange</em>, to get a new ID token using my refresh token.</p>
  
  <blockquote>
    <p><sup>1</sup> There is a rumored <a href="https://www.google.com/search?q=google+identity+toolkit+c%23" rel="nofollow noreferrer">Google Identity Toolkit C# library</a>, but the first result returned by that search I found it by leads to a 404 error instead of documentation. </p>
  </blockquote>
  
  <h2>What Does Work</h2>
  
  <p>Following the <a href="https://firebase.google.com/docs/reference/rest/auth#section-refresh-token" rel="nofollow noreferrer">Firebase guides</a> and the underlying <a href="https://developers.google.com/identity/toolkit/reference/securetoken/rest/v1/token" rel="nofollow noreferrer">Identity Toolkit guides</a>, I have been successful so far interfacing the token exchange endpoint with a <code>cURL</code> command from bash:</p>
  
  <pre class="lang-bash prettyprint-override"><code>curl 'https://securetoken.googleapis.com/v1/token?key=[MY FIREBASE API KEY]' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data 'grant_type=refresh_token&amp;refresh_token=[MY REFRESH TOKEN]'
  </code></pre>
  
  <p>of course, I replace <code>[MY FIREBASE API KEY]</code> with my Firebase Web API key, and <code>[MY REFRESH TOKEN]</code> with the refresh token returned from the sign in/sign up endpoints.</p>
  
  <p>However, despite my many attempts, I have not been able to replicate this <code>cURL</code> command in C#!</p>
  
  <h2>My Failed Attempts</h2>
  
  <h3>1.</h3>
  
  <p>Here's my original code that didn't work.</p>
  
  
  
  <pre><code>public async Task&lt;bool&gt; ExchangeToken()
      {
          FormUrlEncodedContent body = new FormUrlEncodedContent(new Dictionary&lt;string, string&gt;() {
              {"grant_type", "refresh_token" },
              {"refresh_token", Uri.EscapeDataString(user.refreshToken) }
          });
          HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, "https://securetoken.googleapis.com/v1/token?key=" + apiKey);
          message.Content = body;
          message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
          HttpResponseMessage res = await client.SendAsync(message);
      }
  </code></pre>
  
  <p>Unfortunately, I get this <code>401 (Unauthorized)</code> error response:
  </p>
  
  <pre><code>{
    "error": {
      "code": 401,
      "message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
      "status": "UNAUTHENTICATED"
    }
  }
  </code></pre>
  
  <p>This is quite strange, considering that I get a <code>2XX (OK)</code> response from what should be an equivalent <code>cURL</code> command...</p>
  
  <h3>2.</h3>
  
  <p>Thanks to a <a href="https://curl.olsh.me/" rel="nofollow noreferrer">very nice website</a> I just discovered, I was able to "convert" my <code>cURL</code> command into C# code. However, this did not work. I got the exact same error as attempt #1.
  </p>
  
  <pre><code>public async Task&lt;bool&gt; ExchangeToken()
      {
          using (var request = new HttpRequestMessage(new HttpMethod("POST"), "https://securetoken.googleapis.com/v1/token?key=[I WOULD INSERT MY KEY HERE]"))
          {
              request.Content = new StringContent("grant_type=refresh_token&amp;refresh_token=[INSERT REFRESH TOKEN HERE]", Encoding.UTF8, "application/x-www-form-urlencoded");
  
              var res = await client.SendAsync(request);
          }
      }
  </code></pre>
  
  <h2>Possible Leads</h2>
  
  <ol>
  <li>All of my other requests to all of the other endpoints work. There are two notable differences: <strong>1)</strong> the API is technically not Firebase's, but Google Identity Toolkit's. <strong>2)</strong> This is the only endpoint that I'm using that uses a <code>Content-Type</code> header of <code>application/x-www-form-urlencoded</code> instead of <code>application/json</code>.</li>
  </ol>
  
  <h2>My Question / TL;DR</h2>
  
  <blockquote>
    <p>How do I interface with the <a href="https://developers.google.com/identity/toolkit/reference/securetoken/rest/v1/token" rel="nofollow noreferrer">Google Identity Toolkit</a> API's <em>Token Exchange</em> endpoint using C#?
    (Though I'm currently using the HttpClient class, I'm totally open to other solutions! They just have to be compatible with Unity3D.)</p>
  </blockquote>
  
  <p>Thanks in advance!</p>