« Back to home

Accessing API with token from Google Identity Provider

Daj się poznać

In previous posts I wrote about getting id tokens and access tokens from Google Identity Provider. To do this I used the library oidc-token-manager. You can read here and here how I prepared config for this library in order to have a working authentication of a user in Google Identity Provider. I stated that my solution isn’t perfect and actually I treated it as a temporary one. In this post, I’ll write about using tokens fetched from Google to access my sample API. Let’s see what I did and what results it brought.

For the purpose of my testing, I created another project which is in this repository. This time the sample application that I used for this post was created on a Windows operating system because I needed some tools which I am very familiar with like: Visual Studio, ReSharper and dotPeek.

I started in Visual Studio with File -> New -> Project…. I chose the template ASP .NET Web Application*. And then among ASP .NET 5 Templates, I selected the template Web API.

New Project

I copied all the files from my previous experiments to the folder wwwroot. Next to the ValuesController I created another API controller named PublicValuesController with exactly the same content as the ValuesController. I only changed the returned values to distinguish these controllers. After this, the structure of my project looked like this:

Project tree

Next, I installed all the necessary nuget packages so the dependencies in project.json looked like this:

 "dependencies": {
    "Microsoft.AspNet.Authentication.JwtBearer": "1.0.0-rc1-final",
    "Microsoft.AspNet.Diagnostics": "1.0.0-rc1-final",
    "Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final",
    "Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
    "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
    "Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final",
    "Microsoft.Extensions.Configuration.FileProviderExtensions": "1.0.0-rc1-final",
    "Microsoft.Extensions.Logging": "1.0.0-rc1-final",
    "Microsoft.Extensions.Logging.Console": "1.0.0-rc1-final",
    "Microsoft.Extensions.Logging.Debug": "1.0.0-rc1-final"
  },

In the Startup class, the method ConfigureServices looked like this:

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddAuthentication();
    services.AddMvc();
}

And method Configure looked like this:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{                        
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    if (env.IsEnvironment("Development"))
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseIISPlatformHandler();
     
    app.UseDefaultFiles();
    app.UseStaticFiles();

    var options = new JwtBearerOptions
    {
        Authority = "https://accounts.google.com",
        Audience = "342665198077-1fdticgpjke40gddj3r8vghltpgcvb5m.apps.googleusercontent.com",
        RequireHttpsMetadata = false,
        AutomaticAuthenticate = true,
        AutomaticChallenge = false,
        TokenValidationParameters = new TokenValidationParameters
        {
            ValidIssuer = "accounts.google.com"
        }
    };

    app.UseJwtBearerAuthentication(options);

    app.UseMvc();
}

I also granted access to ValuesController only for authenticated user by adding attribute Authorize on the class ValuesController:

[Route("api/[controller]")]
[Authorize]
public class ValuesController : Controller
{
///....

If you want, you can protect all controllers with the configuration in ConfigureServices like this:

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddAuthentication();
    services.AddMvc(config =>
    {
        var policy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .Build();
        config.Filters.Add(new AuthorizeFilter(policy));
    });
}

And then add the attribute AllowAnonymous on these controllers or methods which are accessible for unauthenticated users.
In my sample project, it didn’t matter because I had only two controllers.

Having the setup ready meant I could get access to protected resources with the Google id token which I got using the library oidc-token-manager.

After obtaining the token from Google by clicking Get Token and then clicking Protected, I got following response:

Protected values

When I clicked Protected without token I got a response like this:

Not authorized

Through this sample application, I reached a conclusion. Yes, I know that I made a lot of assumptions which were not true, and I created a lot of simplifications for the purpose of testing but anyway I can get a protected resource with Google tokens fetched by the library oidc-token-manager, which was my goal. My solution is absolutely unready to be used in production because of the token validation. I hardcoded a certificate to validate the token and this is not acceptable because these certificates change quite frequently. To validate tokens through a certificate fetched dynamically, requires me to change the library oidc-token-manager. I don’t want to do this until I attempt other options.

As I mentioned before, I used Visual Studio to create this sample application. I had to debug the 3rd party code a bit to finally get a configuration that works. Now that I have a working application, I can try it in another environment. Let’s see what’s happen when I run this project on Ubuntu. Will ASP .NET CORE turn out to be as portable as people say? Please check out my next post to find what happens when this app is run on Linux.

Related posts:

Comments

comments powered by Disqus