I am able to call or redirect to IdentityServer endpoint "GoogleLogin" from my SPA using html anchor tag href. And then, I got redirected to Google sign-in screen, on a successful sign-in, got a callback to IdentityServer "GoogleResponse" GET endpoint with "returnUrl" pointing to my SPA, now able to create/find user using ASP NET Identity.
Internal users can access the authorised resource using IdentityServer access token but social media users not access it because of their no access token. So from here, the question is how will I get IdentityServer access token and get redirected to my SPA?
[HttpGet("GoogleLogin")]
[AllowAnonymous]
public IActionResult GoogleLogin()
{
var properties = _signInManager.ConfigureExternalAuthenticationProperties(GoogleDefaults.AuthenticationScheme, "/api/Account/GoogleResponse");
return Challenge(properties, GoogleDefaults.AuthenticationScheme);
}
[HttpGet("GoogleResponse")]
[AllowAnonymous]
public async Task<IActionResult> GoogleResponse()
{
ExternalLoginInfo info = await _signInManager.GetExternalLoginInfoAsync();
ApplicationUser user = new ApplicationUser
{
Email = info.Principal.FindFirst(ClaimTypes.Email).Value,
UserName = info.Principal.FindFirst(ClaimTypes.Email).Value,
FullName = info.Principal.FindFirst(ClaimTypes.Name).Value
};
var externalAccessToken = await _userManager.GetAuthenticationTokenAsync(user, GoogleDefaults.AuthenticationScheme, "access_token");
if (info == null)
return Ok(info);
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, false);
string[] userInfo = { info.Principal.FindFirst(ClaimTypes.Name).Value, info.Principal.FindFirst(ClaimTypes.Email).Value };
if (result.Succeeded)
return Ok(result);
else
{
IdentityResult identResult = await _userManager.CreateAsync(user);
await _userManager.AddToRoleAsync(user, "user");
identResult = await _userManager.AddLoginAsync(user, info);
if (identResult.Succeeded)
{
await _signInManager.SignInAsync(user, false);
return Ok(identResult);
}
return BadRequest();
}
}
externalAccessToken is now null here. If I get access token then I will redirect to spa with access token.
Identity server and external login provider configuration
builder.Services.AddIdentityServer(options =>
{
options.IssuerUri = authServerUrl;
options.Events.RaiseErrorEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseErrorEvents = true;
})
.AddAspNetIdentity<ApplicationUser>()
.AddInMemoryApiScopes(IdentityServerConfig.GetApiScopes())
.AddInMemoryApiResources(identityServerSettings.ApiResources)
.AddInMemoryClients(IdentityServerConfig.GetClients())
.AddInMemoryIdentityResources(identityServerSettings.IdentityResources)
.AddDeveloperSigningCredential();
builder.Services.AddAuthentication()
.AddGoogle(opts =>
{
opts.ClientId = "clientid_code";
opts.ClientSecret = "secret_code";
opts.SignInScheme = IdentityConstants.ExternalScheme;
});
builder.Services.AddAuthentication(o =>
{
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Authority = authServerUrl; // base-address of your identityserver
options.TokenValidationParameters.ValidateAudience = false;
options.TokenValidationParameters.ValidTypes = new[] { "at+jwt" };
options.MapInboundClaims = false;
options.TokenValidationParameters.NameClaimType = JwtClaimTypes.Name;
options.TokenValidationParameters.RoleClaimType = JwtClaimTypes.Role;
});
Identity server client set
public static IEnumerable<Client> GetClients()
{
// Clients credentials.
return new List<Client>
{
new Client
{
ClientId = JobChaiAIClientID,
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
AllowAccessTokensViaBrowser = true,
RequireClientSecret = false,
AllowedScopes = {
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Phone,
IdentityServerConstants.StandardScopes.Email,
ScopeConstants.Roles,
ApiName
},
AllowOfflineAccess = true,
RefreshTokenExpiration = TokenExpiration.Sliding,
RefreshTokenUsage = TokenUsage.OneTimeOnly,
},
new Client
{
//clent 2
}
};
}
}