10/4/2019 Admin

Google Authentication in Server Side Blazor

You can log users into your server side Blazor application using Google authentication.

Server-side Blazor provides options for deeper integration between the ‘client side’ and ‘server side’ code because the ‘client side’ code is processed server-side. With server-side Blazor, we end up using less code, and things are a lot less complex because we can trust that the end-user was not able to alter or hack the ‘client side’ code.

If the ‘client side’ code says a user is who they say they are, we can trust them. Otherwise, we have to always make a ‘round trip’ to the server, before permitting operations or returning sensitive data. The ‘round trip’ is still being made (because the ‘client site’ code is being generated ‘server side’), but, our code structure is now cleaner and more streamlined.

Note: This example works without using the Google+ API that Google started to shut down. This sample incorporates the work-around that Microsoft is in the process of rolling out officially. See this GitHub issue for more information.

Note: Many examples, showing Google authentication in an .Net Core application, use the SignInManager. The problem is, the SignInManager requires a data store. This example does not.

The Application


Initially the user clicks the Login button.


They are taken to the Google Login page where they enter their Google username and password.

Note: If the user is already logged into Google, they will be automatically logged in without the need to go through this step.


They are returned to the application.

Their name, and if they have an Avatar, will display.

The Logout button will also appear. Clicking the Logout button will log the user out of the application.

Create The Application


Open Visual Studio 2019 (or higher).


Select Create a new project.


Select Blazor App.


Name the project BlazorGmail.

Add Nuget Package


Right-click on the solution node in the Solution Explorer, and select Manage NuGet Packages for Solution.




Set Up the Google Application


You need to create a Google API Console project to obtain a client ID.

Go to:


Sign in with your Google account and click CONFIGURE A PROJECT.


Give the project a name.


Fill in the information for the remaining screens


Select Other for OAuth client.

Click the CREATE button.


Copy and save the Client ID and Client Secret and click the DONE button.

Note: You can return to the configuration at anytime by going to:


Configure the Authentication Pipeline


Open the appsettings.json file and change all the code to the following:

  {   "Google": {     "Instance": "https://accounts.google.com/o/oauth2/v2/auth",     "ClientId": "{{{ YOUR APP ID }}}",     "ClientSecret": "{{{ YOUR CLIENT SECRET }}}",     "CallbackPath": "/signin-google"   },   "Logging": {     "LogLevel": {       "Default": "Warning",       "Microsoft.Hosting.Lifetime": "Information"     }   },   "AllowedHosts": "*" }

Replace{{{ YOUR APP ID }}} with the Client ID you saved earlier.

Replace{{{ YOUR CLIENT SECRET }}} with the Client Secret you saved earlier.


Open the Startup.cs file.

Add the following using statements to the top of the file:

  using System.Net.Http; using Microsoft.Extensions.Configuration; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies;

Add the following to the Startup class:

          // To hold the values from the appsettings.json file         public IConfiguration Configuration { get; }         public Startup(IConfiguration configuration)         {             Configuration = configuration;         }

Add the following to the bottom of public void ConfigureServices(IServiceCollection services) method:

								services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)                 .AddCookie();             services.AddAuthentication().AddGoogle(options =>             {                 options.ClientId = Configuration["Google:ClientId"];                 options.ClientSecret = Configuration["Google:ClientSecret"];                 options.ClaimActions.MapJsonKey("urn:google:profile", "link");                 options.ClaimActions.MapJsonKey("urn:google:image", "picture");             });             // From: https://github.com/aspnet/Blazor/issues/1554             // Adds HttpContextAccessor             // Used to determine if a user is logged in             // and what their username is             services.AddHttpContextAccessor();             services.AddScoped<HttpContextAccessor>();             // Required for HttpClient support in the Blazor Client project             services.AddHttpClient();             services.AddScoped<HttpClient>();             // Pass settings to other components             services.AddSingleton<IConfiguration>(Configuration);

Add the following to the public void Configure(IApplicationBuilder app, IHostingEnvironment env) method (after the app.UseStaticFiles() line):

              app.UseCookiePolicy();             app.UseAuthentication();


Save the file.

Rebuild the Solution.

It should build without errors.

Create Login and Logout Pages


In the Pages folder, add the following pages using the following code:


@page @model BlazorGmail.Server.Pages.LoginModel @{     ViewData["Title"] = "Log in"; } <h2>Login</h2>


using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; namespace BlazorGmail.Server.Pages {     [AllowAnonymous]     public class LoginModel : PageModel     {         public IActionResult OnGetAsync(string returnUrl = null)         {             string provider = "Google";             // Request a redirect to the external login provider.             var authenticationProperties = new AuthenticationProperties             {                 RedirectUri = Url.Page("./Login",                  pageHandler: "Callback",                  values: new { returnUrl }),             };             return new ChallengeResult(provider, authenticationProperties);         }         public async Task<IActionResult> OnGetCallbackAsync(             string returnUrl = null, string remoteError = null)         {             // Get the information about the user from the external login provider             var GoogleUser = this.User.Identities.FirstOrDefault();             if (GoogleUser.IsAuthenticated)             {                 var authProperties = new AuthenticationProperties                 {                     IsPersistent = true,                     RedirectUri = this.Request.Host.Value                 };                 await HttpContext.SignInAsync(                 CookieAuthenticationDefaults.AuthenticationScheme,                 new ClaimsPrincipal(GoogleUser),                 authProperties);             }             return LocalRedirect("/");         }     } }


@page @model BlazorGmail.Server.Pages.LogoutModel @{     ViewData["Title"] = "Logout"; } <h2>Logout</h2>


using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; namespace BlazorGmail.Server.Pages {     public class LogoutModel : PageModel     {         public string ReturnUrl { get; private set; }         public async Task<IActionResult> OnGetAsync(             string returnUrl = null)         {             returnUrl = returnUrl ?? Url.Content("~/");             // Clear the existing external cookie             try             {                 await HttpContext                     .SignOutAsync(                     CookieAuthenticationDefaults.AuthenticationScheme);             }             catch (Exception ex)             {                 string error = ex.Message;             }             return LocalRedirect("/");         }     } }

Create Login Control


In the Shared folder, add LoginControl.razor using the following code:

@using System.Security.Claims @using Microsoft.AspNetCore.Http @inject IHttpContextAccessor _httpContextAccessor @inject HttpClient Http @if (User.Identity.Name != null) {     <img src="@Avatar" />     <b>You are logged in as: @GivenName @Surname</b>     <a class="ml-md-auto btn btn-primary"        href="/Logout"        target="_top">Logout</a> } else {     <a class="ml-md-auto btn btn-primary"        href="/Login"        target="_top">Login</a> } @code {     private ClaimsPrincipal User;     private string GivenName;     private string Surname;     private string Avatar;     protected override void OnInitialized()     {         base.OnInitialized();         try         {             // Set the user to determine if they are logged in             User = _httpContextAccessor.HttpContext.User;             // Try to get the GivenName             var givenName =                 _httpContextAccessor.HttpContext.User                 .FindFirst(ClaimTypes.GivenName);             if (givenName != null)             {                 GivenName = givenName.Value;             }             else             {                 GivenName = User.Identity.Name;             }             // Try to get the Surname             var surname =                 _httpContextAccessor.HttpContext.User                 .FindFirst(ClaimTypes.Surname);             if (surname != null)             {                 Surname = surname.Value;             }             else             {                 Surname = "";             }             // Try to get Avatar             var avatar =             _httpContextAccessor.HttpContext.User             .FindFirst("urn:google:image");             if (avatar != null)             {                 Avatar = avatar.Value;             }             else             {                 Avatar = "";             }         }         catch { }     } }


To display the Login control, open Shared/MainLayout.razor and change all the code to the following:

@inherits LayoutComponentBase <div class="sidebar">     <NavMenu /> </div> <div class="main">     <div class="top-row px-4">         <!-- ******************************** -->         <LoginControl />         <!-- ******************************** -->     </div>     <div class="content px-4">         @Body     </div> </div>



Google external login setup in ASP.NET Core

Google Developers Dashboard


The project is available on the Downloads page on this site.

You must have Visual Studio 2019 (or higher) installed to run the code.

An error has occurred. This application may no longer respond until reloaded. Reload 🗙