I am working on a .NET MAUI Mobile Application and trying to generate an OAuth 2.0 authentication token to call the Google Play Developer API. I have set up everything as follows:
- Created a project on Google Cloud Console.
- Enabled the Google Play Developer API.
- Configured the OAuth consent screen with the external app type and added the "https://www.googleapis.com/auth/androidpublisher" as a scope.
- Created an OAuth 2.0 Client ID with the application type set to Android, and added the package name along with the SHA-1 fingerprint.
In my .NET MAUI project, I have installed the following NuGet packages:
- Microsoft.Identity.Client
- System.Net.Http.Json
I implemented the OAuth flow for device code authentication. However, when I try to acquire an authentication token, I encounter the following error:
Error requesting device code: { "error": "invalid_client", "error_description": "Invalid client type." } Failed to acquire access token.
I implemented the OAuth flow for device code authentication as below:
public class GoogleAuthService
{
private static readonly HttpClient _httpClient = new HttpClient();
// Set your Client ID
private const string ClientId = "Your_Google_Client_ID";
// Set Google OAuth endpoints
private const string DeviceCodeEndpoint = "https://oauth2.googleapis.com/device/code";
private const string TokenEndpoint = "https://oauth2.googleapis.com/token";
// Scopes needed for the Google Play Developer API
private const string Scope = "https://www.googleapis.com/auth/androidpublisher";
public async Task<string> GetAccessTokenAsync()
{
// Step 1: Request the device code
var deviceCodeResponse = await RequestDeviceCodeAsync();
if (deviceCodeResponse != null)
{
var deviceCode = deviceCodeResponse["device_code"].ToString();
var userCode = deviceCodeResponse["user_code"].ToString();
var verificationUrl = deviceCodeResponse["verification_url"].ToString();
var expiresIn = deviceCodeResponse["expires_in"].ToString();
var interval = int.Parse(deviceCodeResponse["interval"].ToString());
// Instruct the user to visit the URL and input the user code
Console.WriteLine($"Please visit {verificationUrl} and enter the code: {userCode}");
// Step 2: Poll for the token using the device code
return await PollForAccessTokenAsync(deviceCode, interval);
}
return null;
}
private async Task<JObject> RequestDeviceCodeAsync()
{
var parameters = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("client_id", ClientId),
new KeyValuePair<string, string>("scope", Scope)
});
var response = await _httpClient.PostAsync(DeviceCodeEndpoint, parameters);
var responseBody = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
return JObject.Parse(responseBody); // Return the device code response
}
Console.WriteLine($"Error requesting device code: {responseBody}");
return null;
}
private async Task<string> PollForAccessTokenAsync(string deviceCode, int interval)
{
while (true)
{
await Task.Delay(interval * 1000); // Wait for the polling interval
var parameters = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("client_id", ClientId),
new KeyValuePair<string, string>("device_code", deviceCode),
new KeyValuePair<string, string>("grant_type", "urn:ietf:params:oauth:grant-type:device_code")
});
var response = await _httpClient.PostAsync(TokenEndpoint, parameters);
var responseBody = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var tokenResponse = JObject.Parse(responseBody);
var accessToken = tokenResponse["access_token"].ToString();
Console.WriteLine($"Access Token: {accessToken}");
return accessToken; // Return the access token
}
else if (response.StatusCode == System.Net.HttpStatusCode.BadRequest)
{
var error = JObject.Parse(responseBody)["error"].ToString();
if (error == "authorization_pending")
{
Console.WriteLine("Authorization pending, waiting...");
continue; // Keep polling
}
else
{
Console.WriteLine($"Error: {error}");
return null;
}
}
}
}
}
To generate the access token from the below function, I call the GoogleAuthService();
public async void LoginButtonClicked(Object sender, EventArgs e)
{
string accessToken = await _googleAuthService.GetAccessTokenAsync();
if (!string.IsNullOrEmpty(accessToken))
{
// Use the access token to make API calls to Google Play Developer API
Console.WriteLine($"Access Token: {accessToken}");
}
else
{
// Handle failure
Console.WriteLine("Failed to acquire access token.");
}
}
On AndroidManifest.xml file:
<activity android:name="MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="com.googleusercontent.apps.OAuth 2.0 client ID" />
<data android:host="oauth2redirect" />
</intent-filter>
</activity>
What could be causing this "invalid_client" error? Is there something I'm missing in configuring the authentication token using OAuth 2.0 for the .NET MAUI Mobile Application to call the Google Play Developer API?