Search code examples
c#asp.net-coregoogle-oauthasp.net-identity

Google login in ASP.NET Core - user still unauthorized with Google bearer token


I have integrated Google login with my ASP.NET app.

So in callback call from google auth I get code that I use to get user token:

// Must match Google settings
var redirectUri = "https://localhost:7259/GoogleLogin/google-callback";

var tokenRequestParams = new Dictionary<string, string>
{
    { "code", code },
    { "client_id", googleClientId },
    { "client_secret", googleClientSecret },
    { "redirect_uri", redirectUri },
    { "grant_type", "authorization_code" }
};

var tokenResponse = await _httpClient.PostAsync("https://oauth2.googleapis.com/token",
    new FormUrlEncodedContent(tokenRequestParams));

Then, after validating token, I am not sure how to sign user into my applicaiton.

I now use ASP.NET Identity, that implementes endpoint to generate own tokens. They work nice with Authorize attribute when passed as authorization header as bearer token.

With google auth i can return the access token already, but it does not pass Authorize attribute (i get unauthorized response).

Is there any magic setup in startup code so this works out-of-the-box?

Or I have to manually implement my own authorization that will recognize google token and authorize apropriately?


Solution

  • Suggested way in the other answer results in redirects, when trying to access protected endpoints. And I am developing front end that will use fetch to query the data, so browser would block fetch request that resulted in redirect.

    So I had to use slightly different approach for now:

    builder.Services
        .AddAuthentication()
        .AddGoogleOpenIdConnect(googleOptions =>
        {
            googleOptions.ClientId = builder.Configuration["Authentication:Google:ClientId"];
            googleOptions.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"];
        })
        .AddJwtBearer("Google", options =>
        {
            options.Authority = "https://accounts.google.com";
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidIssuer = "https://accounts.google.com",
                ValidateAudience = true,
                // Ensure it's your Google Client ID
                ValidAudience = builder.Configuration["Authentication:Google:ClientId"],
                ValidateLifetime = true
            };
        });
    

    Now it works correctly with AuthorizeAttribute

    Full solution

    I wanted to integrate multiple authorization options. I have started with ASP.NET Identity, that helped me scaffold basic identity services.

    Now that I have integrated also Google OAuth, I needed to allow two types of authentication:

    builder.Services
        .AddAuthentication(IdentityConstants.BearerScheme)
        .AddJwtBearer()
        .AddGoogleOpenIdConnect(googleOptions =>
        {
            googleOptions.ClientId = builder.Configuration["Authentication:Google:ClientId"];
            googleOptions.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"];
        })
        .AddJwtBearer("Google", options =>
        {
            options.Authority = "https://accounts.google.com";
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidIssuer = "https://accounts.google.com",
                ValidateAudience = true,
                // Ensure it's your Google Client ID
                ValidAudience = builder.Configuration["Authentication:Google:ClientId"],
                ValidateLifetime = true
            };
        });
    
    builder.Services.AddAuthorization(options =>
    {
        options.DefaultPolicy = new AuthorizationPolicyBuilder(IdentityConstants.BearerScheme, "Google")
            .RequireAuthenticatedUser()
            .Build();
    });