I am using Identity Server 3 for a central authentication server to a .Net MVC web application I am building.
I have configured the authentication server to use the Open ID Connect
identity provider in order to allow users to authenticate against a multi-tenant Azure Active Directory account, using the Hybrid flow.
Currently, sign in works as expected with my client application redirecting to the authentication server which in turn redirects to Microsoft for login before returning back to my client application with a correctly populated Access Token.
However, when I try to logout I am redirected to Microsoft correctly, but the page stops when it arrives back at the authentication server, rather than continuing back to my client application.
I believe I have setup the post logout redirect correctly as outlined here and I think all of my settings are ok.
When I pull the Identity Server 3 code down and debug it, it is correctly setting the signOutMessageId
onto the query string, but hits the following error inside the UseAutofacMiddleware
method when it is trying to redirect to my mapped signoutcallback
location:
Exception thrown: 'System.InvalidOperationException' in mscorlib.dll
Additional information: Headers already sent
My Authentication Server setup:
app.Map("identity", idsrvApp => {
var idSvrFactory = new IdentityServerServiceFactory();
var options = new IdentityServerOptions
{
SiteName = "Site Name",
SigningCertificate = <Certificate>,
Factory = idSvrFactory,
AuthenticationOptions = new AuthenticationOptions
{
IdentityProviders = ConfigureIdentityProviders,
EnablePostSignOutAutoRedirect = true,
PostSignOutAutoRedirectDelay = 3
}
};
idsrvApp.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
idsrvApp.UseIdentityServer(options);
idsrvApp.Map("/signoutcallback", cb => {
cb.Run(async ctx => {
var state = ctx.Request.Cookies["state"];
ctx.Response.Cookies.Append("state", ".", new Microsoft.Owin.CookieOptions { Expires = DateTime.UtcNow.AddYears(-1) });
await ctx.Environment.RenderLoggedOutViewAsync(state);
});
});
});
My Open Id Connect setup to connect to Azure AD:
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
AuthenticationType = "aad",
SignInAsAuthenticationType = signInAsType,
Authority = "https://login.microsoftonline.com/common/",
ClientId = <Client ID>,
AuthenticationMode = AuthenticationMode.Active,
TokenValidationParameters = new TokenValidationParameters
{
AuthenticationType = Constants.ExternalAuthenticationType,
ValidateIssuer = false,
},
Notifications = new OpenIdConnectAuthenticationNotifications()
{
AuthorizationCodeReceived = (context) =>
{
var code = context.Code;
ClientCredential credential = new ClientCredential(<Client ID>, <Client Secret>);
string tenantId = context.AuthenticationTicket.Identity.FindFirst("tid").Value;
AuthenticationContext authContext = new AuthenticationContext($"https://login.microsoftonline.com/{tenantId}");
AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
code, new Uri(<Identity Server URI>/aad/"), credential, "https://graph.windows.net");
return Task.FromResult(0);
},
RedirectToIdentityProvider = (context) =>
{
string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
context.ProtocolMessage.RedirectUri = appBaseUrl + "/aad/";
context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl + "/signoutcallback";
if (context.ProtocolMessage.RequestType == Microsoft.IdentityModel.Protocols.OpenIdConnectRequestType.LogoutRequest)
{
var signOutMessageId = context.OwinContext.Environment.GetSignOutMessageId();
if (signOutMessageId != null)
{
context.OwinContext.Response.Cookies.Append("state", signOutMessageId);
}
}
return Task.FromResult(0);
}
});
I cannot find any information about the cause of or solution to this problem. How do I configure this to correctly redirect back to my client application?
Edit:
Related discussion on GitHub: https://github.com/IdentityServer/IdentityServer3/issues/2657
I have also tried this with the latest version of Identity Server on MyGet (v2.4.1-build00452) with the same problem.
I have also created a repository that reproduces the issue for me here: https://github.com/Steve887/IdentityServer-Azure/
My Azure AD setup:
GetSignOutMessage
method in the first place. And no, nothing in the logs that I can see. – Puckery