How to Implement Google OAuth2 Authentication in ASP.NET Core
Step-by-step guide to implement Google OAuth2 authentication in ASP.NET Core. Secure your app with Google sign-in, token validation, and user claims.
Go to Tools > Get Tools and Features.
Under Mobile Development with .NET, check ✅ .NET MAUI.
Click Install, and restart Visual Studio after installation.
In your existing solution, right-click on the Solution → Add > New Project.
Search for “.NET MAUI App” and select it.
Enter a name and choose your target version.
After the project is created, you’ll see the project structure.
Once created, you'll see:
├── App.xaml / App.xaml.cs => App lifecycle
├── MainPage.xaml / MainPage.xaml.cs => Home screen
├── Platforms/ => Platform-specific configs
├── MauiProgram.cs => Dependency Injection
├── Resources/ => Images, styles, fonts
├── Views/ => Create LoginPage.xaml here
├── Services/ => Create ApiService.cs, AuthHandler.cs here
A : Right-click the Views folder → Add → New Item → Content Page (XAML) → Name it LoginPage.xaml.
B: Open AppShell.xaml and register the route:
<Shell ... xmlns:views="clr-namespace:JwtAuthMauiApp.Views">
<ShellContent Route="LoginPage" ContentTemplate="{DataTemplate views:LoginPage}" />
</Shell>
Change code and and according need
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="JwtAuthMauiApp.Views.LoginPage"
Title="Login"
BackgroundColor="White">
<ScrollView>
<VerticalStackLayout Padding="30" Spacing="25"
VerticalOptions="Center">
<Label Text="Welcome Back "
FontSize="24"
FontAttributes="Bold"
HorizontalOptions="Center" />
<Label Text="Sign in to continue"
FontSize="16"
TextColor="Gray"
HorizontalOptions="Center" />
<Entry x:Name="EmailEntry"
Placeholder="Email or Username"
Keyboard="Email"
ClearButtonVisibility="WhileEditing" />
<Entry x:Name="PasswordEntry"
Placeholder="Password"
IsPassword="True"
ClearButtonVisibility="WhileEditing" />
<Button Text="Login"
Clicked="OnLoginClicked"
BackgroundColor="#007AFF"
TextColor="White"
CornerRadius="8"
FontAttributes="Bold"
HeightRequest="45" />
<Label x:Name="ErrorLabel"
TextColor="Red"
IsVisible="False"
FontSize="14"
HorizontalOptions="Center"
HorizontalTextAlignment="Center" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
- - - - - - - - - - - - - - - - - - - - - - - -
using var client = new HttpClient();
client.BaseAddress = new Uri("https://your-api-url.com");
var response = await client.PostAsync("/api/auth/login", content);
Set url pass and called you api
await SecureStorage.SetAsync("auth_token", token);
x:Class="JwtAuthMauiApp.Views.LoginPage">
After run project first called app.xaml
Set inside this called for default run login page
public partial class App : Application
{
public App()
{
InitializeComponent();
}
protected override Window CreateWindow(IActivationState? activationState)
{
return new Window(new AppShell());
}
protected override void OnStart()
{
base.OnStart();
Task.Run(async () =>
{
var token = await SecureStorage.GetAsync("auth_token");
MainThread.BeginInvokeOnMainThread(() =>
{
if (!string.IsNullOrEmpty(token))
Shell.Current.GoToAsync("//MainPage");
else
Shell.Current.GoToAsync("//LoginPage");
});
});
}}
Thase code is if token have then show main page else login page
On your logout button’s click event:
SecureStorage.Remove("auth_token");
await Shell.Current.GoToAsync("//LoginPage");
public class AuthHandler : DelegatingHandler
{
protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var token = await SecureStorage.GetAsync("auth_token");
if (!string.IsNullOrEmpty(token))
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
}
var response = await base.SendAsync(request, cancellationToken);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
await SecureStorage.SetAsync("auth_token", string.Empty);
MainThread.BeginInvokeOnMainThread(async () =>
{
await Shell.Current.GoToAsync("//LoginPage");
});
}
return response;
}
}
builder.Services.AddTransient<AuthHandler>();
builder.Services.AddHttpClient("apiClient").AddHttpMessageHandler<AuthHandler>();
Microsoft.Extensions.Http
var email = EmailEntry.Text;
var password = PasswordEntry.Text;
var loginData = new
{
username = EmailEntry.Text,
password = PasswordEntry.Text
};
var loginDataJson = JsonSerializer.Serialize(loginData);
var content = new StringContent(loginDataJson, Encoding.UTF8, "application/json");
<ShellContent Title="Login" Route="LoginPage" ContentTemplate="{DataTemplate views:LoginPage}" />
<!--Forgot Password link-->
<Button Text="Forgot Password?"
Clicked="OnForgotPasswordClicked"
BackgroundColor="Transparent"
TextColor="#007AFF"
FontSize="14"
HorizontalOptions="End"
Padding="0"
BorderWidth="0" />
private async void OnForgotPasswordClicked(object sender, EventArgs e)
{
await Shell.Current.GoToAsync(nameof(ForgotPasswordPage));
}
[HttpPost("forgotpassword")]
public async Task<IActionResult> ForgotPassword([FromBody] ForgotPasswordRequest request)
{
var user = await _userManager.FindByEmailAsync(request.Email);
if (user == null)
return BadRequest("User not found");
var token = await _userManager.GeneratePasswordResetTokenAsync(user);
return Ok(new { token });
}
[HttpPost("resetpassword")]
public async Task<IActionResult> ResetPassword([FromBody] ResetPasswordRequest request)
{
var user = await _userManager.FindByEmailAsync(request.Email);
if (user == null)
return BadRequest("User not found");
var result = await _userManager.ResetPasswordAsync(user, request.Token, request.NewPassword);
if (result.Succeeded)
return Ok("Password reset successful");
return BadRequest(result.Errors);
}
Routing.RegisterRoute("ForgotPasswordPage", typeof(ForgotPasswordPage));
Routing.RegisterRoute("ResetPasswordPage", typeof(ResetPasswordPage));
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="JwtAuthMauiApp.Views.ForgotPasswordPage"
Title="ForgotPasswordPage">
<ScrollView>
<VerticalStackLayout Padding="30" Spacing="20" VerticalOptions="Center">
<Label Text="Forgot Your Password?"
FontSize="24"
FontAttributes="Bold"
HorizontalOptions="Center" />
<Label Text="Enter your email to receive a reset link."
FontSize="14"
HorizontalOptions="Center"
TextColor="Gray" />
<Entry x:Name="EmailEntry"
Placeholder="Email"
Keyboard="Email"
FontSize="16"
BackgroundColor="#f0f0f0"
HeightRequest="50"
Margin="0,20,0,0" />
<Button Text="Send Reset Link"
Clicked="OnSendClicked"
BackgroundColor="#007AFF"
TextColor="White"
CornerRadius="10"
HeightRequest="50" />
<Label x:Name="ResponseLabel"
Text=""
TextColor="Red"
FontSize="14"
IsVisible="False"
HorizontalOptions="Center"
LineBreakMode="WordWrap"
Margin="0,10,0,0"/>
</VerticalStackLayout>
</ScrollView>
</ContentPage>
private async void OnSendClicked(object sender, EventArgs e)
{
var email = EmailEntry.Text;
if (email == null) {
ResponseLabel.Text = "Invalid credentials";
ResponseLabel.IsVisible = true;
}
var data = new ForgotPasswordRequest { Email = email };
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
using var client = new HttpClient { BaseAddress = new Uri("https://localhost:44302") };
var response = await client.PostAsync("/api/forgotpassword", content);
if (response.IsSuccessStatusCode)
{
var tokenJson = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<Dictionary<string, string>>(tokenJson);
var token = result["token"];
var encodedToken = Uri.EscapeDataString(token);
await Shell.Current.GoToAsync($"ResetPasswordPage?email={email}&token={encodedToken}");
}
else
{
ResponseLabel.Text = "Error sending reset request.";
ResponseLabel.IsVisible = true;
}
}
This code return Token And Redirect reset Password Page
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="JwtAuthMauiApp.Views.ResetPasswordPage"
Title="ResetPasswordPage">
<VerticalStackLayout Padding="30" Spacing="20">
<Label Text="Enter New Password" FontSize="18" />
<Entry x:Name="NewPasswordEntry" Placeholder="New Password" IsPassword="True" />
<Entry x:Name="ConfirmPasswordEntry" Placeholder="Confirm Password" IsPassword="True" />
<Button Text="Reset Password" Clicked="OnResetPasswordClicked" />
<Label x:Name="ResponseLabel" Text="" TextColor="Red" IsVisible="False" />
</VerticalStackLayout>
</ContentPage>
[QueryProperty(nameof(Email), "email")]
[QueryProperty(nameof(Token), "token")]
public string Email { get; set; }
public string Token { get; set; }
private async void OnResetPasswordClicked(object sender, EventArgs e)
{
var newPassword = NewPasswordEntry.Text;
var confirmPassword = ConfirmPasswordEntry.Text;
if (string.IsNullOrWhiteSpace(newPassword) || newPassword != confirmPassword)
{
ResponseLabel.Text = "Passwords do not match.";
ResponseLabel.IsVisible = true;
return;
}
var resetData = new ResetPasswordRequest
{
Email = Email,
Token = Token,
NewPassword = newPassword
};
var json = JsonSerializer.Serialize(resetData, new JsonSerializerOptions
{
PropertyNamingPolicy = null
});
var content = new StringContent(json, Encoding.UTF8, "application/json");
using var client = new HttpClient { BaseAddress = new Uri("https://localhost:44302") };
var response = await client.PostAsync("/api/resetpassword", content);
if (response.IsSuccessStatusCode)
{
await DisplayAlert("Success", "Password reset successfully.", "OK");
await Shell.Current.GoToAsync("///LoginPage");
}
else
{
ResponseLabel.Text = "Failed to reset password.";
ResponseLabel.IsVisible = true;
}
}
Step-by-step guide to implement Google OAuth2 authentication in ASP.NET Core. Secure your app with Google sign-in, token validation, and user claims.
Learn how to implement JWT authentication using ASP.NET Core backend and Angular 8 frontend. Secure your app with token-based login in this step-by-step guide.
Continue building secure apps with JWT in Angular 8 and ASP.NET Core. Learn about token refresh, role-based access, and protecting Angular routes in Part 2.
Get in touch with Prishusoft – your trusted partner for custom software development. Whether you need a powerful web application or a sleek mobile app, our expert team is here to turn your ideas into reality.