Best practice: Redirecting to client error page on failed identity server login

Viewed 19

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?

0 Answers
Related