✅ Similar to Blazor WebAssembly
Using Google OAuth 2 for authentication can enhance the user experience and streamline the sign-up process, as many users already have a Google account and can log in to your application using their existing credentials. This tutorial builds on the basic authentication by incorporating Google authentication through the use of Google Identity, allowing for both types of authentication to be used simultaneously. The tutorial covers the following steps:
You can download the example code used in this topic on GitHub.
You must first set up your Google Cloud account by following these steps:
It is recommended to review the Basic Authentication tutorial and ensure that you have a functional basic authentication system in place before proceeding with the following steps.
BlazorSchoolGoogleOAuth.js:
let blazorSchoolAuthenticationStateProviderInstance = null; function blazorSchoolGoogleInitialize(clientId, blazorSchoolAuthenticationStateProvider) { // disable Exponential cool-down /*document.cookie = `g_state=;path=/;expires=Thu, 01 Jan 1970 00:00:01 GMT`;*/ blazorSchoolAuthenticationStateProviderInstance = blazorSchoolAuthenticationStateProvider; google.accounts.id.initialize({ client_id: clientId, callback: blazorSchoolCallback }); } function blazorSchoolGooglePrompt() { google.accounts.id.prompt((notification) => { if (notification.isNotDisplayed() || notification.isSkippedMoment()) { console.info(notification.getNotDisplayedReason()); console.info(notification.getSkippedReason()); } }); } function blazorSchoolCallback(googleResponse) { blazorSchoolAuthenticationStateProviderInstance.invokeMethodAsync("GoogleLogin", { ClientId: googleResponse.clientId, SelectedBy: googleResponse.select_by, Credential: googleResponse.credential }); }
<script src="_framework/blazor.server.js"></script> <script src="js/BlazorSchoolGoogleOAuth.js"></script> <script src="https://accounts.google.com/gsi/client" async defer></script>
public class GoogleResponse { public string ClientId { get; set; } = ""; public string SelectedBy { get; set; } = ""; public string Credential { get; set; } = ""; }
User
class to create a new user from the Google JWT. We use the NuGet package System.IdentityModel.Tokens.Jwt
in the following example:public class User { ... public static User? FromGoogleJwt(string token) { var tokenHandler = new JwtSecurityTokenHandler(); if (tokenHandler.CanReadToken(token)) { var jwtSecurityToken = tokenHandler.ReadJwtToken(token); return new() { Username = jwtSecurityToken.Claims.First(c => c.Type == "name").Value, Password = "" }; } return null; } }
For more information about Google JWT, see https://developers.google.com/identity/gsi/web/reference/js-reference#credential.
AuthenticationStateProvider
, add a method for Google login that can be invoked by JavaScript. For example:public class BlazorSchoolAuthenticationStateProvider : AuthenticationStateProvider, IDisposable { ... [JSInvokable] public void GoogleLogin(GoogleResponse googleResponse) { var principal = new ClaimsPrincipal(); var user = User.FromGoogleJwt(googleResponse.Credential); CurrentUser = user; if (user is not null) { principal = user.ToClaimsPrincipal(); } NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(principal))); } }
A custom button provides more design options, allowing you to create a button that matches your website's style. For instance:
@inject IJSRuntime JSRuntime @inject BlazorSchoolAuthenticationStateProvider BlazorSchoolAuthenticationStateProvider <button type="button" @onclick="SignInWithGoogleAsync">Sign In with Google</button> @code { public async Task SignInWithGoogleAsync() { var blazorSchoolAuthenticationStateProvider = DotNetObjectReference.Create<BlazorSchoolAuthenticationStateProvider>(BlazorSchoolAuthenticationStateProvider); await JSRuntime.InvokeVoidAsync("blazorSchoolGoogleInitialize", "686658243135-3s5lnkgih8so1ckhbhrntuilp2vrf161.apps.googleusercontent.com", blazorSchoolAuthenticationStateProvider); //The following code might not work in some cases //await JSRuntime.InvokeVoidAsync("google.accounts.id.prompt"); //The following code will execute the prompt function and print the reason of not working to the console if fails. await JSRuntime.InvokeVoidAsync("blazorSchoolGooglePrompt"); } }
The <button>
element with @onclick="SignInWithGoogleAsync"
is the custom Sign In with Google
button that the user will click to initiate the sign-in process.
In the SignInWithGoogleAsync
method, the blazorSchoolGoogleInitialize
function is invoked with the client ID and authentication state provider as parameters. Then, the blazorSchoolGooglePrompt
function is used to trigger the sign-in process.
Using the default button provided by Google's sign-in API is a quick and easy solution for adding Google sign-in functionality to your website. While it may enhance the user experience and provide a more professional look to your website, it does have limitations in terms of customization. For instance:
@inject IJSRuntime JSRuntime @inject BlazorSchoolAuthenticationStateProvider BlazorSchoolAuthenticationStateProvider <div id="blazor-school-button"></div> @code { protected override async Task OnInitializedAsync() { var blazorSchoolAuthenticationStateProvider = DotNetObjectReference.Create<BlazorSchoolAuthenticationStateProvider>(BlazorSchoolAuthenticationStateProvider); await JSRuntime.InvokeVoidAsync("blazorSchoolGoogleInitialize", "686658243135-3s5lnkgih8so1ckhbhrntuilp2vrf161.apps.googleusercontent.com", blazorSchoolAuthenticationStateProvider); var element = await JSRuntime.InvokeAsync<IJSObjectReference>("document.getElementById", "blazor-school-button"); await JSRuntime.InvokeVoidAsync("google.accounts.id.renderButton", element, new { theme = "filled_blue", size = "large" }); } }
The <div>
element with id="blazor-school-button"
is where the Google sign-in button will be rendered. In the OnInitializedAsync
method, the blazorSchoolGoogleInitialize
function is invoked with the client ID and authentication state provider as parameters. Then, the getElementById
function is used to get a reference to the div
element where the Google button will be rendered. Finally, the renderButton
function is used to render the Google sign-in button with the specified theme and size.
For more information about rendered button, see https://developers.google.com/identity/gsi/web/reference/js-reference#google.accounts.id.renderButton.