I have been through the docs of identityServer4 and I have set it up to use Microsoft Office 365 as a login provider. When the user has logged in I want to make a button whe
Ok, so I finally got this working. I have created a new project that is using ASP.Net Identity and IdentityServer4 both build on top of ASP.Net Core.
The problem was that I wasn't completely aware of the flow that was used in the external login process.
If you use the boiler plates from both systems you will have an AccountController where the following method will be present:
//
// GET: /Account/ExternalLoginCallback
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
{
if (remoteError != null)
{
ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}");
return View(nameof(Login));
}
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
return RedirectToAction(nameof(Login));
}
// Sign in the user with this external login provider if the user already has a login.
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
if (result.Succeeded)
{
await _signInManager.UpdateExternalAuthenticationTokensAsync(info);
_logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider);
return RedirectToLocal(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl });
}
if (result.IsLockedOut)
{
return View("Lockout");
}
else
{
// If the user does not have an account, then ask the user to create an account.
ViewData["ReturnUrl"] = returnUrl;
ViewData["LoginProvider"] = info.LoginProvider;
var email = info.Principal.FindFirstValue(ClaimTypes.Email);
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email });
}
}
The important part here is the:
await _signInManager.UpdateExternalAuthenticationTokensAsync(info);
This will save your external credentials in the database table associated with your ASP.Net identity. In the table AspNetUserTokens you will now have 3 entries, called something like:
access_token, expires_at and token_type.
These are the tokens that we are interested in, that we can use to access the users credentials somewhere else in our application.
To fetch these tokens in the context of a logged in user:
var externalAccessToken = await _userManager.GetAuthenticationTokenAsync(User, "Microsoft", "access_token");
And to fetch them for a user we fetch from the DB we can use:
var user = _userManager.Users.SingleOrDefault(x => x.Id == "myId");
if (user == null)
return;
var claimsPrincipal = await _signInManager.CreateUserPrincipalAsync(user);
var externalAccessToken = await _userManager.GetAuthenticationTokenAsync(claimsPrincipal, "Microsoft", "access_token");