I have an asp.net MVC and webapi2 application.I want to set OrderId in session and send User to bank website to pay the order and when the bank website will return him to my callback URL in my website I want to get OrderId from the session but it seems that is null. I want to know why it happens?
and another problem is that I use cookie authentication in identity but it doesn't work too. I have set it to 15 days .but it doesn't work too.I don't know but maybe these two problems are related to each other.if someone knows
Why my asp.net identity -user will log out automatically
public ActionResult Pay()
{
Session["orderid"]=12;
}
//callbackurl
public ActionResult Result()
{
var orderid=Convert.ToInt32( Session["orderid"]);//is null
}
the below is in my web.config
<system.web>
<authentication mode="Forms">
<forms loginUrl="~/User/Login" timeout="30">
</forms>
</authentication>
<sessionState timeout="30"></sessionState>
</system.web>
and the below is in startup.cs file
public class Startup
{
public string Issuer { get; set; }
public void Configuration(IAppBuilder app)
{
Issuer = "http://mywebsite.ir/";
ConfigureOAuthTokenGeneration(app);
ConfigureOAuthTokenConsumption(app);
app.UseCors(CorsOptions.AllowAll);
GlobalConfiguration.Configure(WebApiConfig.Register);
AreaRegistration.RegisterAllAreas();
//app.UseWebApi(GlobalConfiguration.Configuration);
RouteConfig.RegisterRoutes(RouteTable.Routes);
//app.UseMvc(RouteConfig.RegisterRoutes);
//ConfigureWebApi(GlobalConfiguration.Configuration);
}
private void ConfigureOAuthTokenGeneration(IAppBuilder app)
{
app.CreatePerOwinContext(() => new LeitnerContext());
app.CreatePerOwinContext<LeitnerUserManager>(LeitnerUserManager.Create);
app.CreatePerOwinContext<LeitnerRoleManager>(LeitnerRoleManager.Create);
// Plugin the OAuth bearer JSON Web Token tokens generation and Consumption will be here
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new Microsoft.Owin.PathString("/User/Login"),
ExpireTimeSpan = TimeSpan.FromDays(15),
Provider = new CookieAuthenticationProvider
{
OnApplyRedirect = ctx =>
{
if (!IsForApi(ctx.Request))
{
ctx.Response.Redirect(ctx.RedirectUri);
}
}
}
});
OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/api/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(15),
Provider = new LeitnerOAuthProvider(),
AccessTokenFormat = new LeitnerJwtFormat(Issuer),
};
app.UseOAuthAuthorizationServer(options);
//app.UseJwtBearerAuthentication(options);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
//app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
}
private bool IsForApi(IOwinRequest request)
{
IHeaderDictionary headers = request.Headers;
return ((headers != null) && ((headers["Accept"] == "application/json") || (request.Path.StartsWithSegments(new PathString("/api")))));
}
private void ConfigureOAuthTokenConsumption(IAppBuilder app)
{
var a = AudiencesStore.AudiencesList["LeitnerAudience"];
string audienceId = a.ClientId;// ConfigurationManager.AppSettings["as:AudienceId"];
byte[] audienceSecret = TextEncodings.Base64Url.Decode(a.Base64Secret/*ConfigurationManager.AppSettings["as:AudienceSecret"]*/);
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audienceId },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(Issuer, audienceSecret)
}
});
}
}
Edit
My WebHost is Plesk Onyx,In the Hosting Setting I see a setting Preferred domain that have three item to select
1- www.jooyabash.ir
2- jooyabash.ir
3- None
Description :Select the URL (either with or without the www. prefix) to which site visitors will be redirected via a SEO-safe HTTP 301 redirect.
When I set it to 1 or 3 i see that session will lost.but when i set it to 2 session until 10 min it will not lost and the payment will compelet in this time
Does any one know why?
Related
I have an ASP.NET Web API project in (running on .NET 4.8 - not .NET Core). I have setup 'Bearer token' authentication by adding:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType))
}
}
And in Startup.cs:
public class Startup1
{
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidIssuer = "https://www.example.com", //some string, normally web url,
}
});
}
}
And in my controller method, I add [Authorize] in my controller API.
But when I call the endpoint in my browser, I checked that it has a bearer token in the http header. The body of the http response is
"Message":"Authorization has been denied for this request."
How can I debug my issue? as I don't see any exception or any message in log.
Could you add these parameters in your code and try:
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { "Any" },
IssuerSecurityKeyProviders = new IIssuerSecurityKeyProvider[] {
new SymmetricKeyIssuerSecurityKeyProvider(issuer, secret)
}
});
var issuer = ConfigurationManager.AppSettings["issuer"];
var secret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["secret"]);
Add these parameters in App config file:
<appSettings>
<add key="issuer" value="http://localhost:xxx/"/>
<add key="secret" value="YourToken"/>
</appSettings>
How to save user data in pure Web Api application, throughout the entire application life such as Session, So that on each request we can use the saved user data.
I saw that in WEB API each request is separate and has no connection to the previous request and therefore can not use Session.
Can anyone help me?
You need to install Microsoft.Owin from Nuget. Then Add this in your start up class.
public void ConfigureAuth(IAppBuilder app)
{
var OAuthOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(20),
Provider = new SimpleAuthorizationServerProvider()
};
app.UseOAuthBearerTokens(OAuthOptions);
app.UseOAuthAuthorizationServer(OAuthOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
}
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
GlobalConfiguration.Configure(WebApiConfig.Register);
}
Then need to add a provider like
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated(); //
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
using (var db = new TESTEntities())
{
if (db != null)
{
var empl = db.Employees.ToList();
var user = db.Users.ToList();
if (user != null)
{
if (!string.IsNullOrEmpty(user.Where(u => u.UserName == context.UserName && u.Password == context.Password).FirstOrDefault().Name))
{
identity.AddClaim(new Claim("Age", "16"));
var props = new AuthenticationProperties(new Dictionary<string, string>
{
{
"userdisplayname", context.UserName
},
{
"role", "admin"
}
});
var ticket = new AuthenticationTicket(identity, props);
context.Validated(ticket);
}
else
{
context.SetError("invalid_grant", "Provided username and password is incorrect");
context.Rejected();
}
}
}
else
{
context.SetError("invalid_grant", "Provided username and password is incorrect");
context.Rejected();
}
return;
}
}
}
You can add number of claim if you required. Then Modify your WebApiConfig
public class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
EnableCorsAttribute cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
}
Then test your token like
Then you pass your token by authorization header. Then get your claims.
Sample of api request
Sample code for get claims data
var principal = this.Request.GetRequestContext().Principal as ClaimsPrincipal;
var claims = principal.Claims.ToList();
var age = claims.FirstOrDefault(c => c.Type == "Age")?.Value;
You can use session variable such as:
Session["FirstName"] = FirstNameTextBox.Text;
Session["LastName"] = LastNameTextBox.Text;
To use session variables :
// When retrieving an object from session state, cast it to
// the appropriate type.
ArrayList stockPicks = (ArrayList)Session["StockPicks"];
// Write the modified stock picks list back to session state.
Session["StockPicks"] = stockPicks;
For mor informations go to : MSDN
I have a .NET MVC and WEB API project. I want to call the WEB API controllers from javascript but I didn't find a way to send the token to my views. I want to add the bearer token in Viewbag variable, using the below code:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
//GetBearerToken doesn't exists
ViewBag.BearerToken = Request.GetOwinContext().GetBearerToken();
}
In _Layout.cshtml, I added the folowing code to set Authorization header for all ajax requests:
<script type="text/javascript">
window.token = '#Viewbag.BearerToken';
// Add Authorization header on ajax requests
if(window.token) {
(function setAjaxRequestsAuthorizationHeader(token) {
$.ajaxPrefilter(function onAjaxPrefilter(options) {
if (!options.beforeSend) {
options.beforeSend = function onBeforeSend(xhr) {
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
}
}
});
}(window.token));
window.token = null;
}
</script>
Below is my Startup configuration method:
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
//app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext(AppDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, User, int>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager),
getUserIdCallback: id => id.GetUserId<int>())
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
}
To get a token I also tried (in the MVC Controller methods):
var token = new ClaimsPrincipal(User.Identity).Claims.FirstOrDefault(x => x.Type == "access_token")?.Value;
But the value of variable token is always null.
I have also inspected all claims values but I didn't find any possible token.
How can I send the token to controller views?
Solved
I solved the problem by doing the following steps:
In Startup.Auth.cs I added the folowing static property:
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
I have created an extension method for ApplicationUser class:
public static async Task<ClaimsIdentity> GenerateUserIdentityAsync(this ApplicationUser user, UserManager<ApplicationUser, int> manager, string type)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
// Genereate Bearer token
if (manager is ApplicationUserManager && type == DefaultAuthenticationTypes.ApplicationCookie)
{
var accessTokenFormat = Startup.OAuthOptions.AccessTokenFormat;
if (accessTokenFormat != null)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
["userName"] = user.UserName
};
AuthenticationProperties properties = new AuthenticationProperties(data);
AuthenticationTicket ticket = new AuthenticationTicket(userIdentity, properties);
var token = accessTokenFormat.Protect(ticket);
userIdentity.AddClaim(new Claim("Access_Token", token));
}
}
return userIdentity;
}
I modified the method OnActionExecuting to send token to the client:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (Request.IsAuthenticated)
{
var identity = (ClaimsIdentity)User.Identity;
ViewBag.BearerToken = identity.Claims.FirstOrDefault(x => x.Type == "Access_Token")?.Value;
}
}
In Startup.Auth.cs use the extension method created at step 2 when creating Identity:
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser, int>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager,
DefaultAuthenticationTypes.ApplicationCookie),
getUserIdCallback: id => id.GetUserId<int>())
I am trying to add authentication to add authentication to an existing MVC 5 application I started from an empty project. I started a new WebAPI project with individual user accounts so I could see how it was configured. I copied over the code having to do with authentication and refactored the namespaces and class names. In the code below, the first line var identityContext = context.Get<IdentityDbContext>() returns null and causes the second line var userStore = new UserStore<AdminAppUser>(identityContext) to throw an error due to a null parameter.
I probably didn't include enough code, as I am very new to MVC Authentication and have a poor understanding of how all the pieces fit together. if I need to include more code please let me know which pieces would be useful. Thank you!
public static AdminAppUserManager Create(IdentityFactoryOptions<AdminAppUserManager> options, IOwinContext context)
{
var identityContext = context.Get<IdentityDbContext>();
var userStore = new UserStore<AdminAppUser>(identityContext);
var manager = new AdminAppUserManager(userStore);
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<AdminAppUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider = new DataProtectorTokenProvider<AdminAppUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
EDIT:
startup.auth.cs
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(AdminAppIdentityDbContext.Create);
app.CreatePerOwinContext<AdminAppUserManager>(AdminAppUserManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
// Uncomment the following lines to enable logging in with third party login providers
//app.UseMicrosoftAccountAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseTwitterAuthentication(
// consumerKey: "",
// consumerSecret: "");
//app.UseFacebookAuthentication(
// appId: "",
// appSecret: "");
//app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
//{
// ClientId = "",
// ClientSecret = ""
//});
}
}
startup.cs:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
}
Edit 2:
public class AdminAppIdentityDbContext : IdentityDbContext<AdminAppUser>
{
public AdminAppIdentityDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static AdminAppIdentityDbContext Create()
{
return new AdminAppIdentityDbContext();
}
}
There should be some sort of ConfigureAuth method that gets called at startup to establish that there is one IdentityDbContext per Owin context. That call will look like:
app.CreatePerOwinContext(IdentityDbContext.Create);
That call should be in the boilerplate that VS generates automatically for you.
You could also just replace
var identityContext = context.Get<IdentityDbContext> with
var identityContext = new AdminAppIdentityDbContext();,
it doesn't really matter. It may spare your time.
I have Web API with OWIN Authentication in Web MVC.
I'm using <authentication> in Web.Config for my Web MVC so it's redirecting to login page.
<authentication mode="Forms">
<forms name="WEB.AUTH" loginUrl="~/login" domain="" protection="All"
timeout="43200" path="/" requireSSL="false" slidingExpiration="true" />
</authentication>
I'm using [System.Web.Http.Authorize] attribute to authorize my Web API. But somehow, the API redirecting to login page same like my MVC app because of above configuration.
what I want to do is keep redirecting function for the Web MVC but returning 401 for Web API. How can I achieve this? should I create a custom authorization attribute for Web API?
--EDIT--
I found the answer from this post SuppressDefaultHostAuthentication in WebApi.Owin also suppressing authentication outside webapi
So I just add a few lines into my Startup.cs. I had all my controllers configured with a "api" prefix route.
HttpConfiguration config = new HttpConfiguration();
//..some OWIN configuration
app.Map("/api", inner =>
{
inner.UseWebApi(config);
});
make sure you put app.Map() after Web Api Configuration lines. Otherwise, it will give error to MVC application.
In .NET Core I have solved it like this, Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Cookie.SameSite = SameSiteMode.Strict;
options.Cookie.Name = "AuthCookie";
options.Events.OnRedirectToAccessDenied = UnAuthorizedResponse;
options.Events.OnRedirectToLogin = UnAuthorizedResponse;
})
....
}
internal static Task UnAuthorizedResponse(RedirectContext<CookieAuthenticationOptions> context)
{
context.Response.StatusCode = (int) HttpStatusCode.Unauthorized;
return Task.CompletedTask;
}
Create a custom AuthorizeAttribute:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Unauthorized");
}
}
If you in the future skip the web.config stuff and use owin to setup your authentication, you could in your Startup.cs do:
var provider = new CookieAuthenticationProvider();
var originalHandler = provider.OnApplyRedirect;
provider.OnApplyRedirect = context =>
{
if (!context.Request.Uri.LocalPath.StartsWith(VirtualPathUtility.ToAbsolute("~/api")))
{
context.RedirectUri = new Uri(context.RedirectUri).PathAndQuery;
originalHandler.Invoke(context);
}
};
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
CookieName = FormsAuthentication.FormsCookieName,
LoginPath = new PathString("/Account/LogOn"),
ExpireTimeSpan = TimeSpan.FromMinutes(240),
Provider = provider
});
This is what worked for me.
Creating a custom attribute:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class NoRedirectAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
}
}
Using the attribute in your controller:
[HttpDelete]
[NoRedirectAuthorizeAttribute(Roles = "Admin")]
[Route("api/v3/thingstodelete/{id=id}")]
public IHttpActionResult DeleteThingToDelete(Guid id)
{
//delete code
}
Here are just overriding the HandleUnauthorizedRequest method of the AuthorizeAttribute. So, instead of sending a redirect (304) to the login page, we send Forbidden(403) HTTP status code.
I struggled with this issue and I came up with a way to only do the redirect if I didn't find the token that I use in the header for my custom manual authorization of my WebApi. This is my setup (notice the Provider object and OnApplyRedirect action)
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
ExpireTimeSpan = TimeSpan.FromMinutes(30),
Provider = new CookieAuthenticationProvider
{
OnApplyRedirect = (ctx) => {
var token = HttpContext.Current.Request.Headers.Get("X-User-Token");
if (token == null) ctx.Response.Redirect(ctx.RedirectUri);
}
}
});
by default wep api at first check cookie but for changing from cookie to jwt I use below attribute
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
above contoller
In order to change the way IIS behaves based on a convention defined by URL, you want to branch your OWIN pipeline. You can do this by using IApplicationBuilder.Map. Assuming a static config:
public void Configure(IApplicationBuilder app)
{
...
app.Map("/api", HandleWebApiRequests);
...
}
private static void HandleWebApiRequests(IApplicationBuilder app)
{
app.UseWebApi(config);
}
The Map method branches the pipeline to the HandleWebApiRequests method based on an URL that begins with "/api".
This should cause 401 errors to behave like they are supposed to and simply return 401 with no redirect.
I needed to configure the StatusCodePage middleware to avoid redirection
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseStatusCodePages();
...
}