We have implemented OAuth using IndentityServer and Owin self hosted web API's. Whenever a client tries to access our authenticated endpoints we use Microsoft.Owin.Security.OpenIdConnect middleware to intercept and redirect the call to the IndentityServer for authentication. In the case of an API call we do not want to return 302, but instead a 401 with a location header with the url of the IdentityServer. We can get the OWIN middleware to return a 401 by setting
AuthenticationMode = AuthenticationMode.Passive
but we're unable to add a location header. How do we accomplish this? We have tried setting the header (see code below), but it doesn't work. It seems the response is build internally by the middleware.
appBuilder.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = idSrvUri.ToString(),
AuthenticationType = WebServiceConstants.OAuthAuthType,
ClientId = "beocloud",
Scope = "openid profile roles",
ResponseType = "id_token token",
AuthenticationMode = AuthenticationMode.Passive,
SignInAsAuthenticationType = WebServiceConstants.OAuthAuthType,
UseTokenLifetime = false,
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = n =>
{
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.AuthenticationRequest)
{
n.ProtocolMessage.RedirectUri = n.Request.Scheme + "://" + n.Request.Host + "/";
n.Response.Headers.Add("Location", new []{n.ProtocolMessage.CreateAuthenticationRequestUrl()});
}
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
{
var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");
if (idTokenHint != null)
{
n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
}
}
return Task.FromResult(0);
}
}
});
}
This is the problem hosting a Web API along side your MVC code -- you're using the wrong security middleware for the API side of it. The OIDC middleware assumes the HTTP calls are from a browser window that it can redirect.
I'd suggest splitting your API into a separate host and pipeline and use a token-based security architecture and middleware. We have lots of samples of this pattern on the github repo.