dushyantp
dushyantp

Reputation: 4728

Microsoft.Maui.Authentication.WebAuthenticator Google login keeps prompting for account selection every time

I have a small .net Maui app which uses Google login to access files in Google Drive.

The code I am using to get the UserCredential is as follows:

Note that the sensitive values are fake and shown here as an example.


const string userEmailKey = "UserEmail";
const string redirectUrl = "com.mytestapp.mytestapp://";
var clientId = "82cef48b-9e0e-46b3-ae05-ab53227e9862.apps.googleusercontent.com";
var tokenUrl = "https://oauth2.googleapis.com/token";

var authUrl = $"https://accounts.google.com/o/oauth2/auth?response_type=code" +
            $"&redirect_uri={redirectUrl}" +
            $"&client_id={clientId}" +
            $"&scope=https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/spreadsheets" +
            $"&include_granted_scopes=true" +
            $"&state=state_parameter_passthrough_value";

var userEmail = Preferences.Get(userEmailKey, null);
if (!string.IsNullOrEmpty(userEmail))
{
    authUrl += $"&login_hint={userEmail}"; // I thought this would force login with the email saved in preferences
}

var authResult = await WebAuthenticator.Default.AuthenticateAsync(
    new Uri(authUrl),
new Uri(redirectUrl));

var codeToken = authResult.Properties["code"];

var parameters = new FormUrlEncodedContent(
    [
        new KeyValuePair<string,string>("grant_type","authorization_code"),
                new KeyValuePair<string,string>("client_id", clientId),
                new KeyValuePair<string,string>("redirect_uri",redirectUrl),
                new KeyValuePair<string,string>("code",codeToken)
    ]
);

HttpClient client = new HttpClient();
var accessTokenResponse = await client.PostAsync(tokenUrl, parameters);
accessTokenResponse.EnsureSuccessStatusCode();

var responseContent = await accessTokenResponse.Content.ReadAsStringAsync();
var accessTokenResponseDict = JsonConvert.DeserializeObject<Dictionary<string, string>>(responseContent);
if (accessTokenResponseDict == null)
{
    throw new NullReferenceException("tokenResponse found to be null");
}

// save email to preferences
var idToken = accessTokenResponseDict["id_token"];
var jwt = new JwtSecurityTokenHandler().ReadJwtToken(idToken);
var email = jwt.Claims.FirstOrDefault(c => c.Type == "email")?.Value;
Preferences.Set(userEmailKey, email);

Google.Apis.Auth.OAuth2.Responses.TokenResponse tokenResponse = new TokenResponse()
{
    AccessToken = accessTokenResponseDict["access_token"],
    ExpiresInSeconds = Convert.ToInt64(accessTokenResponseDict["expires_in"]),
    RefreshToken = accessTokenResponseDict["refresh_token"],
    Scope = accessTokenResponseDict["scope"],
    TokenType = accessTokenResponseDict["token_type"],
};

Google.Apis.Auth.OAuth2.Flows.GoogleAuthorizationCodeFlow googleAuthFlow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer()
{
    ClientSecrets = new ClientSecrets()
    {
        ClientId = clientId
    }
});

var credential = new UserCredential(googleAuthFlow, "user", tokenResponse);

But the account selection page, consent page keep appearing every time the code above runs.

If I add prompt=none to the auth url, the process fails.

Is there a different pattern to cache some value so that once user has logged in and consented, they wont be asked again?

Upvotes: 0

Views: 72

Answers (0)

Related Questions