Generating the authentication token Using OAuth 2.0 for calling Google developer API from .NET MAUI Mobile Application

Sakshi Poojary 95 Reputation points
2024-10-14T08:35:44.2533333+00:00

I am trying to generate the authentication token using OAuth 2.0 for the .NET MAUI Mobile Application using the Google Cloud Console project to call the Google Developer API. For that, I created the project on the Google Cloud console, enabled the Google developer API and configured the consent screen with an external app type, created the OAuth 2.0 client ID with application type Android, and added the package name and SHA-1 fingerprint. I installed the NuGet packages below for the MAUI project.

  1. Microsoft.Identity.Client
  2. System.Net.Http.Json.

I added the below code to implement the OAuth flow on the MAUI Project.


public class GoogleAuthService
        {
            private readonly IPublicClientApplication _pca;

            public GoogleAuthService()
            {
                _pca = PublicClientApplicationBuilder.Create("OAuth 2.0 client ID")
                    .WithRedirectUri("com.googleusercontent.apps.OAuth 2.0 client ID:/oauth2redirect")
                    .Build();
            }
            public async Task<string> AuthenticateAsync()
            {
                try
                {
                    // Scopes for accessing Google APIs
                    string[] scopes = { "https://www.googleapis.com/auth/androidpublisher" };

                    var result = await _pca.AcquireTokenInteractive(scopes)
                        .WithParentActivityOrWindow(MainActivity.CurrentActivity)
                        .ExecuteAsync();

                    Console.WriteLine($"GoogleAPIAccessToken: {result.AccessToken}");
                    return result.AccessToken; // Use this access token for API calls
                }
                catch (Exception ex)
                {
                    // Handle authentication errors
                    Console.WriteLine($"Authentication failed: {ex.Message}");
                    return null;
                }
            }
        }

On MainActivity.cs:

public static MainActivity CurrentActivity { get; private set; }


protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);
    CurrentActivity = this;
    Instance = this;
}


protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
    base.OnActivityResult(requestCode, resultCode, data);
    AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode, resultCode, data);
}

On AndroidManifest.xml:


<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>

To generate the access token from the below function, I call the GoogleAuthService();

private readonly GoogleAuthService _googleAuthService;

_googleAuthService = new GoogleAuthService();


public async void LoginButtonClicked(Object sender, EventArgs e)
{
    string token = await _googleAuthService.AuthenticateAsync();
}

If I click on LoginButton, It navigates to the Microsoft login page, and If I try to log in with mail, it shows the below error.

We're unable to complete your request unauthorized_client: The client does not exist or is not enabled for consumers. If you are the application developer, configure a new application through the App Registrations in the Azure Portal at https://go.microsoft.com/fwlink/?linkid=2083908.

Screenshot:

65A3cT1B

I tried another way to implement OAuth flow on the MAUI Project. While creating the OAuth 2.0 client ID, we can download the OAuth credentials as a JSON file (client_secrets.json). I added this JSON file to the MAUI project under the Platforms, Android folder. After adding the JSON file, I set the Build Action to Content and Copy to Output Directory to Copy Always from the properties of this JSON file. Then, I added the below functions.


public class GoogleAuthService
{
    private static readonly string[] Scopes = { "https://www.googleapis.com/auth/androidpublisher" };
    private const string ApplicationName = "AlertBuddies";

    public async Task<UserCredential> AuthenticateAsync()
    {
        try
        {               
            using (var stream = await FileSystem.OpenAppPackageFileAsync("Platforms/Android/client_secret.json"))
            {
                var credPath = Path.Combine(FileSystem.AppDataDirectory, "token.json");

                var credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GoogleClientSecrets.Load(stream).Secrets,
                    Scopes,
                    "user",
                    CancellationToken.None,
                    new FileDataStore(credPath, true));

                Console.WriteLine($"GoogleAPIAccessToken: {credential.Token.AccessToken}");
                return credential;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Authentication failed: {ex.Message}");
            return null;
        }
    }
}

On AndroidManifest.xml:

<activity android:name="MainActivity"
  android:exported="true">

To generate the access token from the below function, I call the GoogleAuthService();

public

If I click on LoginButton, I get the below error or exception.

Authentication failed: Android/client_secret.json

So, I am unable to generate the authentication token using OAuth 2.0. Is this process correct? How can I generate the authentication token using OAuth 2.0 to call the Google Developer API from the .NET MAUI Mobile Application for subscription status fetch from the Google Play Store?

Please suggest a solution for this.

.NET MAUI
.NET MAUI
A Microsoft open-source framework for building native device applications spanning mobile, tablet, and desktop.
3,955 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Yonglun Liu (Shanghai Wicresoft Co,.Ltd.) 48,666 Reputation points Microsoft Vendor
    2024-10-15T02:00:56.4933333+00:00

    Hello,

    Microsoft.Identity.Client applies to MASL authentication and is beyond its scope for Google account logins.

    The Microsoft Authentication Library (MSAL) enables developers to acquire security tokens from the Microsoft identity platform to authenticate users and access secured web APIs. It can be used to provide secure access to Microsoft Graph, other Microsoft APIs, third-party web APIs, or your own web API. MSAL supports many different application architectures and platforms including .NET, JavaScript, Java, Python, Android, and iOS.

    For scenarios where you use Oauth to log in to your Google account, you could use the WebAuthenticator provided by Maui to implement this functionality. Please refer to the following documentation and examples.

    var authUrl = $"{Your_Google.auth_uri}?response_type=code" +
            $"&redirect_uri=com.maui.login://" +
            $"&client_id={Your_client_id}" +
            $"&scope=https://www.googleapis.com/auth/userinfo.email" +
            $"&include_granted_scopes=true" +
            $"&state=state_parameter_passthrough_value";
     
     
    var callbackUrl = "your_callbackUrl";
     
    try
    {
        var response = await WebAuthenticator.AuthenticateAsync(new WebAuthenticatorOptions()
        {
            Url = new Uri(authUrl),
            CallbackUrl = new Uri(callbackUrl)
        });
     
        var codeToken = response.Properties["code"];
     
        var parameters = new FormUrlEncodedContent(new[]
        {
                new KeyValuePair<string,string>("grant_type","authorization_code"),
                new KeyValuePair<string,string>("client_id",Your_client_id),
                new KeyValuePair<string,string>("redirect_uri",callbackUrl),
                new KeyValuePair<string,string>("code",codeToken),
            });
     
     
        HttpClient client = new HttpClient();
        var accessTokenResponse = await client.PostAsync(your_token_url, parameters);
        // This is a custom class used to deserialize JSON data.
        LoginResponse loginResponse;
     
        if (accessTokenResponse.IsSuccessStatusCode)
        {
            var data = await accessTokenResponse.Content.ReadAsStringAsync();
     
            loginResponse = JsonConvert.DeserializeObject<LoginResponse>(data);
        }
    }
    catch (TaskCanceledException e)
    {
        // Use stopped auth
    }
    

    Best Regards,

    Alec Liu.


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.