Search code examples
c#asp.net-coreauthorizationgoogle-oauthblazor-server-side

Blazor server : Struggling to add policy to Google authentication to restrict access to my account only


After successfully making my app authenticate my app with Google, I am trying to add a policy which will only restrict access to my google account.

I used this tutorial to get google authentication working : https://www.youtube.com/watch?v=H4G0kqIG1_0

and I refered to this stack overflow question to add my policy:

ASP.NET Core authentication with Google only for a specific account

The answer to this question didn't seem to work out for me, my attempt to get the claim returns a null value and I don't know why.

below is the relevant code on Startup.cs

services.AddAuthentication("Cookies")
                .AddCookie(opt =>
                {
                    opt.Cookie.Name = "GoogleAuth";
                    opt.LoginPath = "/auth/google-login";
                })
                .AddGoogle(opt =>
                {
                    opt.ClientId = Environment.GetEnvironmentVariable("GOOGLE_CLIENT_ID");
                    opt.ClientSecret = Environment.GetEnvironmentVariable("GOOGLE_CLIENT_SECRET");
                    opt.Scope.Add("openid");
                    opt.Scope.Add("profile");
                    opt.Scope.Add("email");
                    opt.Events.OnCreatingTicket = context =>
                    {
                        string picture = context.User.GetProperty("picture").GetString();
                        string name = context.User.GetProperty("name").GetString();
                        string given_name = context.User.GetProperty("given_name").GetString();

                        context.Identity.AddClaim(new Claim("picture", picture));
                        context.Identity.AddClaim(new Claim("name", name));
                        context.Identity.AddClaim(new Claim("given_name", given_name));
                        return Task.CompletedTask;
                    };
                });

services.AddAuthorization(opt =>
            {
                opt.AddPolicy("MeOnly", policy =>
                {
                    policy.RequireAssertion(context =>
                    {
                        // returns a null value
                        var name = context.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Name)?.Value;

                        /*
                         *  I want to add some logic to only give access to my Google account
                         */
                        return false;
                    });
                });
            });


Solution

  • You can restrict access by account id or email claim (or any other claim, for that matter).

    Create a policy and require a specific claim value. Here I'm using a FallbackPolicy which ensures all endpoints are protected with this policy unless specified otherwise.

    services.AddAuthorization(options =>
        options.FallbackPolicy = new AuthorizationPolicyBuilder(
                GoogleDefaults.AuthenticationScheme
            )
            .RequireAuthenticatedUser()
            .RequireClaim(ClaimTypes.Email, "[email protected]")
            .Build()
    );
    

    It might be useful to make this configurable. Add this to appsettings.json

    {
      "AuthorizedEmails": [
        "[email protected]",
        "[email protected]"
      ],
      // ...
    }
    

    Then we can read this configuration at runtime and apply it:

    var authorizedEmails = Configuration.GetSection("AuthorizedEmails").Get<string[]>();
    services.AddAuthorization(options =>
        options.FallbackPolicy = new AuthorizationPolicyBuilder(
                GoogleDefaults.AuthenticationScheme
            )
            .RequireAuthenticatedUser()
            .RequireClaim(ClaimTypes.Email, authorizedEmails)
            .Build()
    );
    

    Further info