One of the most common questions asked about IIS on the newsgroups as well as Microsoft Product Support is "why am I getting 401 Access Denied"?

There are many, many possible causes and variations, but from the IIS perspective, the top-level, logical categories are fixed. This information can help dramatically narrow down the scope of any investigation, but unfortunately, few people know to take advantage of this information. This is what I am going to address with this entry - how to use and diagnose the 401.x error codes on IIS.

Step 1: Determine the SubStatus Code

When you get a 401 response in the browser from IIS and you want to troubleshoot it, the first thing you should do is determine what "type" (i.e. HTTP substatus) of 401 it is.

Starting with IIS 6.0, the IIS web log files located at:

%SYSTEMROOT%\System32\LogFiles\W3SVC###\*.log

record both the HTTP status and substatus code, which when combined with the Win32 error code can aid to troubleshoot many 401 errors. The W3C log entries look like the following, with the HTTP status, substatus, and Win32 error codes highlighted.

#Software: Microsoft Internet Information Services 6.0
#Version: 1.0
#Date: 2005-05-21 05:39:27
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) sc-status sc-substatus sc-win32-status 
2005-05-21 05:39:27 192.168.0.101 GET /VirtualServer/VSWebApp.exe view=1 1024 WEBBROWSER\User 192.168.0.101 Mozilla/4.0+(User-Agent) 200 0 0
2005-05-21 05:39:27 192.168.0.101 GET /VirtualServer/scripts/VSScripts.js - 1024 - 192.168.0.101 Mozilla/4.0+(User-Agent) 401 2 5
2005-05-21 05:39:27 192.168.0.101 GET /VirtualServer/scripts/VSScripts.js - 1024 - 192.168.0.101 Mozilla/4.0+(User-Agent) 401 1 2148074254
2005-05-21 05:39:27 192.168.0.101 GET /VirtualServer/scripts/VSScripts.js - 1024 WEBBROWSER\User 192.168.0.101 Mozilla/4.0+(User-Agent) 304 0 0

You can also get the substatus code from the HTML response itself, but web browsers like Internet Explorer have options like "Show Friendly HTTP Errors" which obscure the detailed error response by making them "simple" and "user friendly", so if you want the real error response, you need to turn off that option.

Unfortunately, prior to IIS 6.0, the IIS web log files are useless in distinguishing 401 substatus because it does not even record it. Your only option is to figure this out from the HTML response itself, assuming the 401.x Custom Error pages for that URL's scope are configured to send different HTML pages for each type of error.

Step 2: Determine Course of Action

Once you have determined the HTTP substatus code, you can start narrowing down the types of failures and causes. The following are the fixed categories that IIS reports. I will give detailed explanation of what each means as well as some common causes/solutions (obviously not exhaustive).

401.1 Denied by Invalid User Credentials

This error indicates that IIS failed to obtain an NT user token with which to execute the request.

In a nutshell, IIS expects to have a NT user token at the end of Authentication (even anonymous authentication - see this URL for details), and if this does not happen, you get 401.1.

Some common causes include:

  • The client gave the wrong username/password (including none at all). This could be from incorrect cached auto-login attempt by the browser, or from a user login dialog from the browser.
  • Invalid Kerberos configuration - on IIS6, if you have a customized Application Pool Identity AND Integrated Authentication is used AND the web server is in a domain, you will mysteriously get 401.1 unless you configure SETSPN *or* change Integrated Authentication to favor NTLM. See the following URLs on Application Pool Identity, Integrated Authentication in IIS, and Constrained Delegation configuration as well as this URL on additional Kerberos-related troubleshooting for more information
  • You enabled Anonymous authentication, yet you still get 401.1 for all requests. One common cause is if the configured anonymous user credentials stored in the IIS metabase configuration file is DIFFERENT than the user principle's credentials in reality (i.e. mismatched password). In all cases, the preferred solution is to manually synchronize the username/password of the anonymous user principle in IIS with that of the real user principle. I have seen many amazing variations of this cause, including:
    • For testing purposes, the user types in his/her OWN username/password as anonymous user credentials at some point in the past and forgets about it. Later, when password policy forces them to change their password, the anonymous user credentials stored in IIS configuration is now mismatched with reality. On subsequent anonymous requests, IIS fails to login and obtain a NT user token for anonymous authentication and fails with 401.1, and it looks like IIS is just plain buggy and could not even support anonymous authentication.
    • I have also seen the reverse happen - user configures IIS to use their username/password as anonymous user, and when they changed their password, web server traffic quickly causes IIS to incorrectly login with wrong user credentials too many times, causing their user account to be locked out. These users now complain that their user account is mysteriously getting locked out as soon as it is unlocked, even before they log in anywhere.
    • On upgrading from IIS 5 to IIS 6, IIS Sub Authentication (i.e. the "allow IIS to control anonymous user's password" feature) is enabled by default for compatibility. This allows IIS to log in the anonymous user principle without actually keeping the user credentials in sync, and anonymous authentication looks good while in IIS 5 Compatibility Mode. However, as soon as you switch into IIS 6 Worker Process Isolation Mode, Sub Authentication is disabled because it requires a privileged process identity like Local System (which is a known and quite unnecessary security risk for the lowly purpose of password sync). This means that IIS 6 now tries to log in the anonymous user credentials stored in the metabase, which has probably NEVER been kept in sync with reality through the upgrade... and you now get 401.1 for every single anonymous request. To a casual user, it looks like switching into IIS 6's native mode simply breaks anonymous authentication and the rest of the website.
  • The server has been reconfigured to deny necessary login privileges for the authenticating user or its containing group (either anonymous or through some authentication protocol). This can be done through automated re-application of Group Policy for domain members, DCPROMO to/from Domain Controller, or static application of security templates. What ends up happening is that the server-side reconfiguration may remove Local/Remote Login rights for that user, impose new restrictions (like Login hours, Logon type), etc... preventing IIS from successfully logging in the user to execute requests and resulting in 401.1.
  • Your event log could be full for some reason - see KB 832981.

401.2 Denied by Server Configuration

This error indicates that the web server is configured to require certain authentication protocols for communication, but the browser failed to use any of those authentication protocols. The corrective action should be to either configure to require an authentication protocol acceptable to the client, or use a client that satisfies the server authentication protocol requirements.

  • A common cause of this issue happens with the older Netscape/Mozilla browser clients and an IIS web server configured to require Integrated Authentication. These browser clients did not understand Integrated Authentication, so when IIS required Integrated Authentication and the browsers repeatedly ignored those responses, IIS will return 401.2 indicating that the browser failed to use an authentication protocol required by the server. Newer Mozilla browsers like FireFox do not have this deficiency.
  • Another possible cause is when using Integrated Authentication over the Internet. Integrated Authentication (NTLM) is a connection-based authentication protocol, meaning that an authenticated connection between a client and server is the only proof of authenticity. This works fine in Intranet scenarios, but for Internet scenarios a lot of network devices in between the client and server can either not support or mishandle NTLM (such as Proxy Server connection pooling/multiplexing), causing unexpected 401.2.

    Here is how it happens: since NTLM is connection-based authentication, once a client successfully authenticates using NTLM, it often re-uses its end of the connection and simply sends anonymous requests over it. Now, assume an intervening proxy server pools connections between client and server, is unaware of NTLM, and independently decides to send the client's request over *another* connection in its pool (instead of the already authenticated one) to the server. This causes the client's anonymous request to be sent to the server over a new, unauthenticated connection, and the server dutifully rejects it with a 401.2 since the server requires Integrated authentication. The 401.2 rejection is totally unexpected by the client since it thought it was re-using an authenticated connection and did not initiate any re-authentication. Yup, fun... ;-)

    Common variations of an "intervening proxy server" include:

    • "Web Accelerators", such as the Google Web Accelerator. These programs basically act like a local "caching proxy" such that requests for content has a higher chance of coming from your local hard drive than over the network, thus "speeding up" apparent web access.

    • Web Anonymizers - these programs basically disguise your own IP and other request characteristics with their proxy's IP and characteristics, and this is shared amongst all their users, thus providing anonymity through numbers.

    • Sniffer tools like Fiddler for IE - these programs act like "Web Accelerators" except instead of caching request/responses, it chooses to selectively capture and display those request/responses for user analysis.

    • Web Access Proxies for some broadband providers or preset Company proxies - these are the traditional obvious proxies.

401.3 Denied by Resource ACL

This error indicates that the web server was able to authentication and obtain SOME NT user token to process the HTTP request (you still have to determine WHICH user's token...), but that NT user token lacks the FileSystem ACLs to access the requested resource. This is the typical "access denied" due to missing file ACLs that people assume, and yes, you will likely need to adjust ACLs to resolve this issue.

However, realize that all of the OTHER 401.x errors have nothing to do with ACLs, so I recommend AGAINST tweaking resource ACLs to "Everyone: Full Control" to remove ACL issues from the picture. You should be able to determine the exact user that fails to have ACLs to the resource, and just adjust ACLs for that user on the necessary resources and resolve the issue

Common causes include:

  • Wrong/Missing ACLs on the file for the authenticated user. You need to change the ACLs or change the user to an identity that has correct ACLs on the file.
  • You are not authenticating with the authentication protocol you think, and thus the user principle may be unexpected. Reconfigure the authentication protocols as-appropriate so that you end up running as user identity you expect on the server.
  • If your content is on a UNC share, you may have mismatched NTFS ACLs vs. UNC Share ACLs.

A useful tool to pragmatically determine access-denied to file resources is File Monitor.

401.4 Denied by Custom ISAPI Filter

This error indicates that some ISAPI Filter running on that request sent back a structured 401 response of some sort.

The reasons why the ISAPI Filter is returning such 401 responses are completely arbitrary and uncontrollable by IIS. You will need to determine WHICH ISAPI Filter is returning this response and obtain support for this ISAPI Filter to resolve the issue.

401.5 Denied by Custom ISAPI/CGI Web Application

This error indicates that some ISAPI Extension or CGI Web Application sent back a structured 401 response of some sort.

The reasons why the CGI/ISAPI are returning such 401 responses are completely arbitrary and uncontrollable by IIS. You will need to determine WHICH CGI/ISAPI is returning the response and obtain support for it.

In the case of requests that execute .DLL or .EXE requests, the CGI/ISAPI binary is clear. In the case of requests with Extensions that have Application Mapping (i.e. the .asp extension is mapped to the ASP ISAPI DLL Script Engine), you need to look up the extension and its associated Application Mapping in the URL's scope to determine the Script Engine to obtain support.

Starting with IIS6, it is also possible for Wildcard Application Mappings to execute on any request within its configured scope prior to executing the actual handler for the request. It is conceptually like how an ISAPI Filter can act on a .asp request before the ASP ISAPI handler processes the request.

A popular scenario for Wildcard Application Mapping is to implement custom authentication, so a 401.5 on a .html file may indicate presence of a Wildcard Application Mapping-based custom authentication. To the astute reader - .html is handled by the Static File Handler by default, which will only return 401.3 for access denied... so if you see a 401.5 involved with a resource like .html that is usually NOT associated with an Application Mapping which can only return 401.5 for access denied... you know either a Wildcard Application Mapping, or non-standard Application Mapping for .html is involved.

To determine which Wildcard Application Mapping is involved on a request, you have to use the IIS Manager to look up the EFFECTIVE Wildcard Application Mapping for that request, starting from the web page of the URL itself and working up the directory tree until you find the nearest Mapping definition. Yes, it is a major hassle prior to IIS7 to determine the effective Application Mapping of a request for support purposes.

Starting with IIS7, you can use Failed Request Tracing to determine all handlers that executed in sequence on a given request, which will show exactly what module / application mapping caused the 401.5. This makes it extremely easy to identify the faulty DLL without trying to calculate effective Wildcard Application Mapping configuration.

Conclusion

401.1 through 401.3 errors are associated with IIS request processing and allow the logical interpretations and assumptions that I listed above.

Meanwhile, the 401.4 and 401.5 errors are the most arbitrary to diagnose since custom ISAPI DLLs and CGI EXE can cause IIS to behave in non-obvious manners. Thus, much of the logical assumptions about 401.x do not apply.

I hope that this information has been useful in deciphering the 401.x errors from IIS. If you have additional questions, feel free to post a comment or post a private question via the "contact" link.

Recently, we have also released a tool, AuthDiag, to help troubleshoot IIS access denied issues. You can download it from this location. In particular, it has a feature to hook in to various failure points in IIS and directly troubleshoot what is failing on a given request - you need to see and try it out!

Good Luck.

//David