During my career, I’ve been involved in multiple web projects where the social login feature was a must. There are many tutorials that explain how to integrate Social Login into a website, but very few that show how to integrate Social Login in a Web API solution.
This post is designed to offer a step-by-step tutorial on how to integrate Google Sign-In and manage users in your Web API back-end effortlessly.
The sample code is written using ASP.NET Core 3.1 for back-end and Angular 9 for front-end, but this can be implemented in any other server/front-end frameworks. A live demo can be accessed here, and the source code is available on GitHub.
Official guide from Google: Authenticate with a backend server.
Clone the repo
Git clone: https://github.com/ionutneagos/social-login-web-api.git
Solution structure:
The logic to validate users is implemented in the WebApi project and the Infrastructure project is used for data persistence.
Navigate to WebApi Project -> appsettings.json, and update it according to your credentials.
To validate Google users, we need to add a route/action to receive the Google token from the front-end application. In the AuthController class I added the GoogleAuthenticate post action, which requires a model as a parameter: GoogleUserRequest.
Note: You can choose to send only one parameter – string id_token. I chose to use a model to be able to send extra information.
//Google User Request Model
namespace WebApi.Models.Auth
{
using Newtonsoft.Json;
using System.ComponentModel.DataAnnotations;
public class GoogleUserRequest
{
public const string PROVIDER = “google”;
[JsonProperty(“idToken”)]
[Required]
public string IdToken {get; set;}
}
}
// GoogleAuthenticate
[AllowAnonymous]
[HttpPost]
public async Task GoogleAuthenticate([FromBody] GoogleUserRequest request)
{
if (!ModelState.IsValid)
return BadRequest(ModelState.Values.SelectMany(it => it.Errors).Select(it => it.ErrorMessage));
return Ok(GenerateUserToken(await _userService.AuthenticateGoogleUserAsync(request)));
}
We need to validate the IdToken value. To achieve this, I used the Google.Apis.Auth package. Note, this is for .NET Core 3.1 . When I wrote this sample, I used 1.45.0-beta01 version. The previous versions are not compatible with .net core 3.1.
public async Task AuthenticateGoogleUserAsync(GoogleUserRequest request)
{
Payload payload = await ValidateAsync(request.IdToken, new ValidationSettings
{
Audience = new[] { Startup.StaticConfig[“Authentication:Google:ClientId”] }
});
return await GetOrCreateExternalLoginUser(GoogleUserRequest.PROVIDER, payload.Subject, payload.Email, payload.GivenName, payload.FamilyName);
}
When you are validating the token, it’s very important to create the audience for your Google Client ID. This way you will ensure that the token is for your application.
Based on Google auth server response, in the method GetOrCreateExternalLoginUser we have to check if the user is already registered with that email address, and if not, we will create a new one in the database.
private async Task GetOrCreateExternalLoginUser(string provider, string key, string email, string firstName, string lastName)
{
var user = await _userManager.FindByLoginAsync(provider, key);
if (user != null)
return user;
user = await _userManager.FindByEmailAsync(email);
if (user == null)
{
user = new AppUser
{
Email = email,
UserName = email,
FirstName = firstName,
LastName = lastName,
Id = key,
};
await _userManager.CreateAsync(user);
}
var info = new UserLoginInfo(provider, key, provider.ToUpperInvariant());
var result = await _userManager.AddLoginAsync(user, info);
if (result.Succeeded)
return user;
return null;
}
As the last step, in GenerateUserToken, based on GetOrCreateExternalLoginUser result, we generate a JWT token and send it back to the front-end.
private UserToken GenerateUserToken(AppUser user)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(Startup.StaticConfig[“Authentication:Jwt:Secret”]);
var expires = DateTime.UtcNow.AddDays(7);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, user.Id) ,
new Claim(JwtRegisteredClaimNames.Sub, Startup.StaticConfig[“Authentication:Jwt:Subject”]),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToString()),
new Claim(ClaimTypes.Name, user.Id),
new Claim(ClaimTypes.Surname, user.FirstName),
new Claim(ClaimTypes.GivenName, user.LastName),
new Claim(ClaimTypes.NameIdentifier, user.UserName),
new Claim(ClaimTypes.Email, user.Email)
}),
Expires = expires,
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
Issuer = Startup.StaticConfig[“Authentication:Jwt:Issuer”],
Audience = Startup.StaticConfig[“Authentication:Jwt:Audience”]
};
var securityToken = tokenHandler.CreateToken(tokenDescriptor);
var token = tokenHandler.WriteToken(securityToken);
return new UserToken
{
UserId = user.Id,
Email = user.Email,
Token = token,
Expires = expires
};
}
After completing all these steps, the server is ready and you can start it.
Note: Automatic migrations are applied on application startup, so you do not need to generate them manually. For doing this, I used EFCore.AutomaticMigrations package.
Front-End
The front-end is built as an Angular standalone application using npm commands. In order to remove dependencies between UI component frameworks and Angular, the front-end HTML/CSS uses plain and simple Bootstrap and is built with Angular 9 using the Angular CLI. This reduces dependency restrictions on any UI component framework.
Install dependencies running npm install command.
Navigate to Angular.Client/GoogleLogin/src/environments -> environments.ts, and update it according to your credentials:
To use Google’s login window, I installed Angular 9 Social Login package: angularx-social-login.
In the components folder, I created a simple angular component, which on click event will trigger the flow for the Google authentication process:
The response is passed as an input parameter to our logic to validate users, which is implemented in the AuthenticateService.
This is pretty much it. You can now start the angular client using ng serve command and test it out.
Don’t forget to check out the live demo for the final result. If you have any specific issues/questions in a similar setup, please let us know, along with how you fixed them. We will create an updated post to address them.
Discover materials from our experts, covering extensive topics including next-gen technologies, data analytics, automation processes, and more.
Ready to take your business to the next level?