I'm trying to access a Purchase Status API from my ASP.NET web server using Google APIs .NET Client Library which is a recommended way for using Purchase API v1.1. However, the Authorization page of this API suggests direct web requests to Google's OAuth2 pages instead of using the corresponding client libraries.
OK, I tried both methods with all variations I could imagine and both of them lead to "The remote server returned an error: (400) Bad Request.".
Now what I've done to get to my point. First I've made all steps 1-8 under the Creating an APIs Console project of the Authorization page. Next I generated a refresh token as described there. During refresh token generation I chose the same Google account as I used to publish my Android application (which is in published beta state now).
Next I've created a console C# application for test purposes in Visual Studio (may be console app is the problem?) and tried to call the Purchase API using this code (found in some Google API examples):
private static void Main(string[] args)
{
var provider =
new WebServerClient(GoogleAuthenticationServer.Description)
{
ClientIdentifier = "91....751.apps.googleusercontent.com",
ClientSecret = "wRT0Kf_b....ow"
};
var auth = new OAuth2Authenticator<WebServerClient>(
provider, GetAuthorization);
var service = new AndroidPublisherService(
new BaseClientService.Initializer()
{
Authenticator = auth,
ApplicationName = APP_NAME
});
var request = service.Inapppurchases.Get(
PACKAGE_NAME, PRODUCT_ID, PURCHASE_TOKEN);
var purchaseState = request.Execute();
Console.WriteLine(JsonConvert.SerializeObject(purchaseState));
}
private static IAuthorizationState GetAuthorization(WebServerClient client)
{
IAuthorizationState state =
new AuthorizationState(
new[] {"https://www.googleapis.com/auth/androidpublisher"})
{
RefreshToken = "4/lWX1B3nU0_Ya....gAI"
};
// below is my redirect URI which I used to get a refresh token
// I tried with and without this statement
state.Callback = new Uri("https://XXXXX.com/oauth2callback/");
client.RefreshToken(state); // <-- Here we have (400) Bad request
return state;
}
Then I tried this code to get the access token (I found it here: Google Calendar API - Bad Request (400) Trying To Swap Code For Access Token):
public static string GetAccessToken()
{
var request = WebRequest.Create(
"https://accounts.google.com/o/oauth2/token");
request.Method = "POST";
var postData =
string.Format(
@"code={0}&client_id={1}&client_secret={2}&redirect_uri={3}&grant_type=authorization_code",
// refresh token I got from browser
// also tried with Url encoded value
// 4%2FlWX1B3nU0_Yax....gAI
"4/lWX1B3nU0_Yax....gAI",
// ClientID from Google APIs Console
"919....1.apps.googleusercontent.com",
// Client secret from Google APIs Console
"wRT0Kf_bE....w",
// redirect URI from Google APIs Console
// also tried Url encoded value
// https%3A%2F%2FXXXXX.com%2Foauth2callback%2F
"https://XXXXX.com/oauth2callback/");
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
using (var dataStream = request.GetRequestStream())
{
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
}
try
{
// request.GetResponse() --> (400) Bad request again!
using (var response = request.GetResponse())
{
using (var dataStream = response.GetResponseStream())
{
using (var reader = new StreamReader(dataStream))
{
var responseFromServer = reader.ReadToEnd();
var jsonResponse = JsonConvert.DeserializeObject<OAuth2Response>(responseFromServer);
return jsonResponse.access_token;
}
}
}
}
catch (Exception ex) { var x = ex; }
return null;
}
So, to sum up all my long story:
- Is it possible at all to pass OAuth2 authorization using either of methods above from a C# Console Application (without user interaction)?
- I've double checked the redirect URI (since I saw a lot of discussed troubles because of it here on stackoverflow) and other parameters like ClientID and ClientSecret. What else I could do wrong in the code above?
- Do I need to URL encode a slash in the refresh token (I saw that the first method using client library does it)?
- What is the recommended way of achieving my final goal (Purchase API access from ASP.NET web server)?