Search code examples
oauth-2.0google-oauthangular-oauth2-oidc

Can't authenticate Google access token on my net.core backend


I'm testing for the first time, how to use net.core API + Angular with Google Authentication, I already achieved to get an access token with my UI application, basically I developed a POC that uses OAuthService and once all the handshake is ok, you are able to call this method:

this.oAuthService.getAccessToken()

Which will result in a valid token (presumably)

So, now is the time to inject that in the backend and authenticate every single request that goes from the UI to the backend. For this, I created a REST API which has Swagger, I added the statements to be able to manually inject the bearer token (for testing purposes) and now i'm trying to test a very simple endpoint to confirm the authentication works.

This is the CURL sent by Swagger to the backend, on which we can see the authorization header is added properly:

curl -X 'GET' \
  'https://localhost:7103/AuthenticationMethod/GetAll' \
  -H 'accept: text/plain' \
  -H 'Authorization: ya29.a0AfB_byBis8NBGFASFeCEeMg4m9CJY0kusHndtCyMqHL8zBtpp8DsOaL26iuFhW2FpxrroNveQqoVCT5Ug2iPCM0uCTT5MYlBdDfGrjPsGyUR6L3mxwu2R9xlAzRJfZTOsp97swdMRJW2419H-kX5_6klnV27fXcvYlQaCgYKASESARMSFQHGX2MiuCAIYY4jhQkgsH2IwFKBFw0170'

For my surprise, I get all the time a 401 error, and it's not able to authenticate in any way.

I created this extension method to configure the Authentication, so this is basically it:

public static void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{

    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = "https://accounts.google.com", 
            ValidAudience = configuration["Authentication:Google:ClientId"], 
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Authentication:Google:ClientSecret"]))
        };
    });

}

Other points to consider.

  1. swagger runs in "https://localhost:7103", so just in case, I included this url in the Authorized JavaScript Origins and Authorized redirect URIs

  2. Secret and client are ok.

  3. When I try to copy/paste the result of "GetAccessToken" from the UI, and try to see its content in jwt.io, this page throws an error, which is strange, like the token is not valid.

  4. For the UI part, I developed the Oauth handshake using "angular-oauth2-oidc", I tried to use "social-login" but got tired of the amount of errors that I have with that.

What am I doing wrong here? I tried several examples on how to authenticate my backend for google and nothing seems to work.


Solution

  • I found the solution, thanks to a "related question" here from stack overflow that poped up a week later.

    First, will change the "configure" method to this, which I took from another suggestion from another post, and failed at that time:

      public static void ConfigureServices(IServiceCollection services, IConfiguration configuration)
            {
                var googleClientId = configuration["Authentication:Google:ClientId"];
                var googleIssuer = "https://accounts.google.com";
    
                services.AddAuthentication(options =>
                {
                    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                })
                    .AddJwtBearer(options =>
                {
                    options.Authority = googleIssuer;
                    options.Audience = googleClientId;
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = false,
                        ValidateAudience = false,
                        ValidateLifetime = false,
                        ValidateIssuerSigningKey = false,
                        ValidIssuer = googleIssuer,
                        ValidAudience = googleClientId,
                    };
                });
    
            }
    

    And second, it is basically a problem in the documentation, it is not quite clear (or at least not for me) that the access_token is NOT meant to authenticate your user in your OWN backend, it is used to authenticate your user in GOOGLE APIS (like get email, or similar)

    This explains why when I added my token (from getAccessToken()) and tried to parse it in JWT.IO, it thrown an error.

    The solution, instead of using:

    this.oAuthService.getAccessToken()
    

    I should use:

    this.oAuthService.getIdToken()
    

    Found this solution thanks to: https://developers.google.com/identity/openid-connect/openid-connect#exchangecode

    but not because it's properly explained, instead it was because the id_token is highlighted that IT IS A JWT TOKEN, I tried that token instead, and my backend started to work without issues.

    enter image description here