question

Peterjc-4736 avatar image
0 Votes"
Peterjc-4736 asked Peterjc-4736 commented

Prevent browser authentication ASP.NET Web API dialog on 401

I have an existing ASP.NET Webforms / MVC application (it uses a mixture of technologies), to which I want to add a Web API to use for external ajax API calls (to replace older web services and WCF).

The existing ASP.NET WebForms application uses forms authentication, so if a login fails, it will redirect to a Webforms login page. I do NOT not want this for the Web API, I always just want to return json data (not a bunch of HTML).

To disable the login form, I found I could add the following to Global.asax:

 protected void Application_BeginRequest(Object sender, EventArgs e)
 {      
     string testPath = $"{Context.Request.ApplicationPath.ToLowerInvariant()}/{BaseConstants.WebApiRoutePrefix}/";
     bool isWebApiRequest = Context.Request.Path.ToLower().Contains(testPath);      
    
     if (isWebApiRequest && FormsAuthentication.IsEnabled && !Context.Request.IsAuthenticated)
     {
         Context.Response.SuppressFormsAuthenticationRedirect = true;  <---- this disables the login page
     }
 }

The above does stop the login page, but I then noticed the Web API calls could go through with no authentication at all.

So I created an authorization attribute to use for the Web API controllers:

 public class WebApiAuthorizationAttribute : System.Web.Http.AuthorizeAttribute
 {
     public override void OnAuthorization(HttpActionContext actionContext)
     {
         .. 
         // if not auth returns a HttpStatusCode.Unauthorized,
     }
 }

This code (almost) all works fine, however, just before I get the response for my Ajax call (in my case from an Angular app), I always get a browser login dialog...

235613-image.png

If I click cancel, I then get the response back in the Angular application with the JSON etc I am after.

Can I stop the dialog from displaying, so I just get back any error JSON?

Thanks in advance


dotnet-aspnet-generaldotnet-aspnet-webapi
image.png (22.5 KiB)
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

LanHuang-MSFT avatar image
0 Votes"
LanHuang-MSFT answered Peterjc-4736 commented

Hi @Peterjc-4736,
Browser authentication forms are typically used in intranets that have Windows authentication. Instead of forms authentication.
Take a look at IIS express configurations: %USERPROFILE%\Documents\IISExpress\config\applicationhost.config Make sure authentication settings are correct and not affecting you.
There should not be any entry for your application. Also the default value for windows authentication should be false: <windowsAuthentication enabled="false">
You can open the Properties window in Visual Studio. Set Anonymous Authentication to Enabled and Windows Authentication to Disabled.
https://docs.microsoft.com/en-us/troubleshoot/developer/webapps/aspnet/development/forms-based-authentication
Best regards,
Lan Huang


If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks for the suggestion. I am using full IIS, however looking in the hosts file there is not much.

Im the asp.net webforms application (which also contains the webAPI), we have

  <authentication mode="Forms">
       <forms name="Login" loginUrl="Login.aspx" protection="All" timeout="10" path="/" />
     </authentication>

So no windows auth anywhere (just the forms)


0 Votes 0 ·

Hi @Peterjc-4736,
Browsers pop up login prompts generally because the HTTP status is 401 and
The WWW authentication header exists in the response.
There are two things you can try:

  • If you can control the HTTP response, you can remove the WWW-authentication header from the response. Or explicitly set the www-authenticate header to an empty string to make it work.
    (err, req, res, next) => { if (err) { res._headers['www-authenticate'] = '' return res.json(err) } }

  • If you have access to the code for the web service that is returning the 401. Simply change the service to return a 403 (Forbidden) in this situation instead 401. The browser will not prompt for credentials in response to a 403. 403 is the correct code for an authenticated user that is not authorized for a specific resource.

Best regards,
Lan Huang

1 Vote 1 ·

Thankyou!

I tried setting WWW-authentication to empty, but still seemed to get the dialog, however, returning the 403 instead of a 401 has fixed the issue.

0 Votes 0 ·
Bruce-SqlWork avatar image
0 Votes"
Bruce-SqlWork answered Bruce-SqlWork commented

typically you add a header to the Ajax call to identify it as an Ajax call. then in OnAuthorization you check for the header. if present, instead of redirecting to the login (default processing) just return the error json with Response.Write & Response.End

· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks for the suggestion. I have not added any header, but I am detecting the request using the URI, as the ajax calls all have the api/ prefix.
eg
I have

 protected void Application_BeginRequest(Object sender, EventArgs e)
  {      
      string testPath = $"{Context.Request.ApplicationPath.ToLowerInvariant()}/{BaseConstants.WebApiRoutePrefix}/";
      bool isWebApiRequest = Context.Request.Path.ToLower().Contains(testPath);      
        
      if (isWebApiRequest && FormsAuthentication.IsEnabled && !Context.Request.IsAuthenticated)
      {
          Context.Response.SuppressFormsAuthenticationRedirect = true;  <---- this disables the login page
      }
  }

Before I added this, it was redirecting to our own login page, and this stopped it.

Also in the WebAPI controller OnAuthorize() and am just returning json with the error, and this does come back to the client, however, just before that we get the login dialog as in the question (this is NOT one of our own dialogs, I have no idea where it is coming from)

0 Votes 0 ·

the dialog is the browsers response to a 401 error with basic authentication. ajax support basic authentication.

0 Votes 0 ·