My security architecture consists of an Identity Server, JS Client and an external provider. The Identity Server uses authorization code flow.
A simplified login process looks as follows: User clicks login in the JS Client -> redirected to Identity Server -> redirected to external provider. I then use the external provider to authenticate the user. When sucessfully redirected back to my Identity Server I then check in a database if the user is active or not. This happens in the AccountController:
[HttpGet]
[Route("callback")]
public async Task<IActionResult> Callback()
{
var result = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
...
var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";
// My check if user is active or not
var isActive = await IsActiveAsync(providerUserId);
if (!isActive)
{
var errorRedirectUri = "https://127.0.0.1/error_page";
return Redirect(errorRedirectUri);
}
var context = await Interaction.GetAuthorizationContextAsync(returnUrl);
await Events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, providerUserId, subjectId, true, context?.Client.ClientId));
return Redirect(returnUrl);
}
If the user is active, the flow works perfectly. Access and refresh tokens are created, user is signed into the Identity Server and redirected back to the client. I am having issues in handling the case, where the user sucessfully logged in to the external provider but is not active in my database. In this case I want to redirect to a error page of the client.
An obvious way to do it, is to configure a error redirect uri, to which the user is redirected to in the mentioned scenario. But this does not feels like the proper way.
I also considered implementing the ProfileService.IsActiveAsync(...) method, but this just resulted in redirecting the user back to the external provider login after setting context.IsActive = false;. With no option of returning to the JS Client without valid credentials of an active user.
public async Task IsActiveAsync(IsActiveContext context)
{
// My check if user is active or not
context.IsActive = await IsActiveAsync(context.Subject);
}
So my question is: What is the apropriate way of redirecting the user to a client-side error page when the user was sucessfully authenticated at the external provider but was not marked as active in my own database?