Some Background Information
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 case1, I have resorted to interfacing with Firebase's REST API through C#'s HttpClient
class (which comes with System.Net.Http
).
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 ID Token and a Refresh Token. ID Tokens expire; refresh tokens do not. When the ID Token expires, I must call another endpoint, called the Token Exchange, to get a new ID token using my refresh token.
1 There is a rumored Google Identity Toolkit C# library, but the first result returned by that search I found it by leads to a 404 error instead of documentation.
What Does Work
Following the Firebase guides and the underlying Identity Toolkit guides, I have been successful so far interfacing the token exchange endpoint with a cURL
command from bash:
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&refresh_token=[MY REFRESH TOKEN]'
of course, I replace [MY FIREBASE API KEY]
with my Firebase Web API key, and [MY REFRESH TOKEN]
with the refresh token returned from the sign in/sign up endpoints.
However, despite my many attempts, I have not been able to replicate this cURL
command in C#!
My Failed Attempts
1.
Here's my original code that didn't work.
public async Task<bool> ExchangeToken()
{
FormUrlEncodedContent body = new FormUrlEncodedContent(new Dictionary<string, string>() {
{"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);
}
Unfortunately, I get this 401 (Unauthorized)
error response:
{
"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"
}
}
This is quite strange, considering that I get a 2XX (OK)
response from what should be an equivalent cURL
command...
2.
Thanks to a very nice website I just discovered, I was able to "convert" my cURL
command into C# code. However, this did not work. I got the exact same error as attempt #1.
public async Task<bool> 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&refresh_token=[INSERT REFRESH TOKEN HERE]", Encoding.UTF8, "application/x-www-form-urlencoded");
var res = await client.SendAsync(request);
}
}
Possible Leads
- All of my other requests to all of the other endpoints work. There are two notable differences: 1) the API is technically not Firebase's, but Google Identity Toolkit's. 2) This is the only endpoint that I'm using that uses a
Content-Type
header ofapplication/x-www-form-urlencoded
instead ofapplication/json
.
My Question / TL;DR
How do I interface with the Google Identity Toolkit API's Token Exchange 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.)
Thanks in advance!