identityserver4openid-connectoidc-client-jsangular-auth-oidc-client

IdentityServer4 Windows Authentication Missing Callback implementation


The documentation to setup Windows Authentication is here: https://docs.identityserver.io/en/latest/topics/windows.html

But I have no idea how to configure the Callback() method referred to in the line RedirectUri = Url.Action("Callback"), or wethere or not I'm even supposed to use that.

I tried manually redirecting back to the https://<client:port>/auth-callback route of my angular app but I get the error:

Error: No state in response
    at UserManager.processSigninResponse (oidc-client.js:8308)

Does someone have a suggested Callback method I can use with an SPA using code + pkce ? I've tried searching Google but there are no current example apps using Windows Authentication and the ones that do exist are old.


Solution

  • Take a look at the ExternalLoginCallback method. I've also pasted the version of the code as of 26 Oct 2020 below for future reference incase the repo goes away.

        /// <summary>
        /// Post processing of external authentication
        /// </summary>
        [HttpGet]
        public async Task<IActionResult> ExternalLoginCallback()
        {
            // read external identity from the temporary cookie
            var result = await HttpContext.AuthenticateAsync(IdentityConstants.ExternalScheme);
            if (result?.Succeeded != true)
            {
                throw new Exception("External authentication error");
            }
    
            // lookup our user and external provider info
            var (user, provider, providerUserId, claims) = await FindUserFromExternalProviderAsync(result);
            if (user == null)
            {
                // this might be where you might initiate a custom workflow for user registration
                // in this sample we don't show how that would be done, as our sample implementation
                // simply auto-provisions new external user
                user = await AutoProvisionUserAsync(provider, providerUserId, claims);
            }
    
            // this allows us to collect any additonal claims or properties
            // for the specific prtotocols used and store them in the local auth cookie.
            // this is typically used to store data needed for signout from those protocols.
            var additionalLocalClaims = new List<Claim>();
            additionalLocalClaims.AddRange(claims);
    
            var localSignInProps = new AuthenticationProperties();
            ProcessLoginCallbackForOidc(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForWsFed(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForSaml2p(result, additionalLocalClaims, localSignInProps);
    
            // issue authentication cookie for user
            // we must issue the cookie maually, and can't use the SignInManager because
            // it doesn't expose an API to issue additional claims from the login workflow
            var principal = await _signInManager.CreateUserPrincipalAsync(user);
            additionalLocalClaims.AddRange(principal.Claims);
    
            var name = principal.FindFirst(JwtClaimTypes.Name)?.Value ?? user.Id;
            await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.Id, name));
    
            // issue authentication cookie for user
            var isuser = new IdentityServerUser(principal.GetSubjectId())
            {
                DisplayName = name,
                IdentityProvider = provider,
                AdditionalClaims = additionalLocalClaims
            };
    
            await HttpContext.SignInAsync(isuser, localSignInProps);
    
            // delete temporary cookie used during external authentication
            await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
    
            // validate return URL and redirect back to authorization endpoint or a local page
            var returnUrl = result.Properties.Items["returnUrl"];
            if (_interaction.IsValidReturnUrl(returnUrl) || Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
    
            return Redirect("~/");
        }