Rectangle 27 280

When it was first developed, System.Web.Mvc.AuthorizeAttribute was doing the right thing - older revisions of the HTTP specification used status code 401 for both "unauthorized" and "unauthenticated".

If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials.

In fact, you can see the confusion right there - it uses the word "authorization" when it means "authentication". In everyday practice, however, it makes more sense to return a 403 Forbidden when the user is authenticated but not authorized. It's unlikely the user would have a second set of credentials that would give them access - bad user experience all around.

Consider most operating systems - when you attempt to read a file you don't have permission to access, you aren't shown a login screen!

Thankfully, the HTTP specifications were updated (June 2014) to remove the ambiguity.

From "Hyper Text Transport Protocol (HTTP/1.1): Authentication" (RFC 7235):

The 401 (Unauthorized) status code indicates that the request has not been applied because it lacks valid authentication credentials for the target resource.

From "Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content" (RFC 7231):

The 403 (Forbidden) status code indicates that the server understood the request but refuses to authorize it.

Interestingly enough, at the time ASP.NET MVC 1 was released the behavior of AuthorizeAttribute was correct. Now, the behavior is incorrect - the HTTP/1.1 specification was fixed.

Rather than attempt to change ASP.NET's login page redirects, it's easier just to fix the problem at the source. You can create a new attribute with the same name (AuthorizeAttribute) in your website's default namespace (this is very important) then the compiler will automatically pick it up instead of MVC's standard one. Of course, you could always give the attribute a new name if you'd rather take that approach.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAuthenticated)
        {
            filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
}
filterContext.HttpContext.User.Identity.IsAuthenticated
filterContext.HttpContext.Request.IsAuthenticated

Great idea - I've updated the answer.

> You can create a new attribute with the same name (AuthorizeAttribute) in your website's default namespace then the compiler will automatically pick it up instead of MVC's standard one. This results in an error: The type or namespace 'Authorize' could not be found ( are you missing a directive or an assembly reference?) Both using System.Web.Mvc; and the namespace for my custom AuthorizeAttribute class are referenced in the controller. To solve this I had to use [MyNamepace.Authorize]

@DePeter the spec never says anything about a redirect so why is a redirect a better solution? This alone kills ajax requests without a hack in place to solve it.

asp.net mvc - Why does AuthorizeAttribute redirect to the login page f...

asp.net-mvc authentication authorization
Rectangle 27 280

When it was first developed, System.Web.Mvc.AuthorizeAttribute was doing the right thing - older revisions of the HTTP specification used status code 401 for both "unauthorized" and "unauthenticated".

If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials.

In fact, you can see the confusion right there - it uses the word "authorization" when it means "authentication". In everyday practice, however, it makes more sense to return a 403 Forbidden when the user is authenticated but not authorized. It's unlikely the user would have a second set of credentials that would give them access - bad user experience all around.

Consider most operating systems - when you attempt to read a file you don't have permission to access, you aren't shown a login screen!

Thankfully, the HTTP specifications were updated (June 2014) to remove the ambiguity.

From "Hyper Text Transport Protocol (HTTP/1.1): Authentication" (RFC 7235):

The 401 (Unauthorized) status code indicates that the request has not been applied because it lacks valid authentication credentials for the target resource.

From "Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content" (RFC 7231):

The 403 (Forbidden) status code indicates that the server understood the request but refuses to authorize it.

Interestingly enough, at the time ASP.NET MVC 1 was released the behavior of AuthorizeAttribute was correct. Now, the behavior is incorrect - the HTTP/1.1 specification was fixed.

Rather than attempt to change ASP.NET's login page redirects, it's easier just to fix the problem at the source. You can create a new attribute with the same name (AuthorizeAttribute) in your website's default namespace (this is very important) then the compiler will automatically pick it up instead of MVC's standard one. Of course, you could always give the attribute a new name if you'd rather take that approach.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAuthenticated)
        {
            filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
}
filterContext.HttpContext.User.Identity.IsAuthenticated
filterContext.HttpContext.Request.IsAuthenticated

Great idea - I've updated the answer.

> You can create a new attribute with the same name (AuthorizeAttribute) in your website's default namespace then the compiler will automatically pick it up instead of MVC's standard one. This results in an error: The type or namespace 'Authorize' could not be found ( are you missing a directive or an assembly reference?) Both using System.Web.Mvc; and the namespace for my custom AuthorizeAttribute class are referenced in the controller. To solve this I had to use [MyNamepace.Authorize]

@DePeter the spec never says anything about a redirect so why is a redirect a better solution? This alone kills ajax requests without a hack in place to solve it.

asp.net mvc - Why does AuthorizeAttribute redirect to the login page f...

asp.net-mvc authentication authorization
Rectangle 27 279

When it was first developed, System.Web.Mvc.AuthorizeAttribute was doing the right thing - older revisions of the HTTP specification used status code 401 for both "unauthorized" and "unauthenticated".

If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials.

In fact, you can see the confusion right there - it uses the word "authorization" when it means "authentication". In everyday practice, however, it makes more sense to return a 403 Forbidden when the user is authenticated but not authorized. It's unlikely the user would have a second set of credentials that would give them access - bad user experience all around.

Consider most operating systems - when you attempt to read a file you don't have permission to access, you aren't shown a login screen!

Thankfully, the HTTP specifications were updated (June 2014) to remove the ambiguity.

From "Hyper Text Transport Protocol (HTTP/1.1): Authentication" (RFC 7235):

The 401 (Unauthorized) status code indicates that the request has not been applied because it lacks valid authentication credentials for the target resource.

From "Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content" (RFC 7231):

The 403 (Forbidden) status code indicates that the server understood the request but refuses to authorize it.

Interestingly enough, at the time ASP.NET MVC 1 was released the behavior of AuthorizeAttribute was correct. Now, the behavior is incorrect - the HTTP/1.1 specification was fixed.

Rather than attempt to change ASP.NET's login page redirects, it's easier just to fix the problem at the source. You can create a new attribute with the same name (AuthorizeAttribute) in your website's default namespace (this is very important) then the compiler will automatically pick it up instead of MVC's standard one. Of course, you could always give the attribute a new name if you'd rather take that approach.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAuthenticated)
        {
            filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
}
filterContext.HttpContext.User.Identity.IsAuthenticated
filterContext.HttpContext.Request.IsAuthenticated

Great idea - I've updated the answer.

> You can create a new attribute with the same name (AuthorizeAttribute) in your website's default namespace then the compiler will automatically pick it up instead of MVC's standard one. This results in an error: The type or namespace 'Authorize' could not be found ( are you missing a directive or an assembly reference?) Both using System.Web.Mvc; and the namespace for my custom AuthorizeAttribute class are referenced in the controller. To solve this I had to use [MyNamepace.Authorize]

@DePeter the spec never says anything about a redirect so why is a redirect a better solution? This alone kills ajax requests without a hack in place to solve it.

asp.net mvc - Why does AuthorizeAttribute redirect to the login page f...

asp.net-mvc authentication authorization
Rectangle 27 234

  • Failed validation: 403 Forbidden ("The server understood the request, but is refusing to fulfill it"). Contrary to popular opinion, RFC2616 doesn't say "403 is only intended for failed authentication", but "403: I know what you want, but I won't do that". That condition may or may not be due to authentication.
  • Trying to add a duplicate: 409 Conflict ("The request could not be completed due to a conflict with the current state of the resource.")

You should definitely give a more detailed explanation in the response headers and/or body (e.g. with a custom header - X-Status-Reason: Validation failed).

@deamon: That is not the specification, that's Wikipedia, i.e. someone's opinion on "what HTTP status codes mean"; note that the page essentialy says "this is what Apache means with 403, this is what IIS means with 403", and nowhere does it reference the official RFC. You seem to be repeating "403 means whatever Apache says". NOT. The actual RFC (which is the relevant document, not Apache's implementation, not IIS' implementation, not anyone else's implementation) is here: w3.org/Protocols/rfc2616/rfc2616-sec10.html

"10.4.4 403 Forbidden The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead." I see no emphasis there ("SHOULD/SHOULD NOT" are RFC 2119 keywords, not emphasis); that's your idea what "forbidden" means, not RFC's.

I like this answer, but still see one small problem. According to the spec, when a 403 is returned, "the request SHOULD NOT be repeated". However, returning a 409 "is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request". In the case of a duplicate, I think 403 is then more appropriate, as you cannot really resolve the conflict (except by deleting the previous instance of the resource).

For the error message itself you should modify the reason phrase, so sending the header HTTP/1.0 403 Form validation errors is the cleanest way to go.

IMO, 422 "Unprocessable Entity" makes much more sense. My reasoning is that it's not that the server refuses to fulfill request, it's that the server can't fulfill the request.

REST HTTP status codes for failed validation or invalid duplicate - St...

http rest http-status-codes
Rectangle 27 233

  • Failed validation: 403 Forbidden ("The server understood the request, but is refusing to fulfill it"). Contrary to popular opinion, RFC2616 doesn't say "403 is only intended for failed authentication", but "403: I know what you want, but I won't do that". That condition may or may not be due to authentication.
  • Trying to add a duplicate: 409 Conflict ("The request could not be completed due to a conflict with the current state of the resource.")

You should definitely give a more detailed explanation in the response headers and/or body (e.g. with a custom header - X-Status-Reason: Validation failed).

@deamon: That is not the specification, that's Wikipedia, i.e. someone's opinion on "what HTTP status codes mean"; note that the page essentialy says "this is what Apache means with 403, this is what IIS means with 403", and nowhere does it reference the official RFC. You seem to be repeating "403 means whatever Apache says". NOT. The actual RFC (which is the relevant document, not Apache's implementation, not IIS' implementation, not anyone else's implementation) is here: w3.org/Protocols/rfc2616/rfc2616-sec10.html

"10.4.4 403 Forbidden The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead." I see no emphasis there ("SHOULD/SHOULD NOT" are RFC 2119 keywords, not emphasis); that's your idea what "forbidden" means, not RFC's.

I like this answer, but still see one small problem. According to the spec, when a 403 is returned, "the request SHOULD NOT be repeated". However, returning a 409 "is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request". In the case of a duplicate, I think 403 is then more appropriate, as you cannot really resolve the conflict (except by deleting the previous instance of the resource).

For the error message itself you should modify the reason phrase, so sending the header HTTP/1.0 403 Form validation errors is the cleanest way to go.

IMO, 422 "Unprocessable Entity" makes much more sense. My reasoning is that it's not that the server refuses to fulfill request, it's that the server can't fulfill the request.

REST HTTP status codes for failed validation or invalid duplicate - St...

http rest http-status-codes
Rectangle 27 233

  • Failed validation: 403 Forbidden ("The server understood the request, but is refusing to fulfill it"). Contrary to popular opinion, RFC2616 doesn't say "403 is only intended for failed authentication", but "403: I know what you want, but I won't do that". That condition may or may not be due to authentication.
  • Trying to add a duplicate: 409 Conflict ("The request could not be completed due to a conflict with the current state of the resource.")

You should definitely give a more detailed explanation in the response headers and/or body (e.g. with a custom header - X-Status-Reason: Validation failed).

@deamon: That is not the specification, that's Wikipedia, i.e. someone's opinion on "what HTTP status codes mean"; note that the page essentialy says "this is what Apache means with 403, this is what IIS means with 403", and nowhere does it reference the official RFC. You seem to be repeating "403 means whatever Apache says". NOT. The actual RFC (which is the relevant document, not Apache's implementation, not IIS' implementation, not anyone else's implementation) is here: w3.org/Protocols/rfc2616/rfc2616-sec10.html

"10.4.4 403 Forbidden The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead." I see no emphasis there ("SHOULD/SHOULD NOT" are RFC 2119 keywords, not emphasis); that's your idea what "forbidden" means, not RFC's.

I like this answer, but still see one small problem. According to the spec, when a 403 is returned, "the request SHOULD NOT be repeated". However, returning a 409 "is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request". In the case of a duplicate, I think 403 is then more appropriate, as you cannot really resolve the conflict (except by deleting the previous instance of the resource).

For the error message itself you should modify the reason phrase, so sending the header HTTP/1.0 403 Form validation errors is the cleanest way to go.

IMO, 422 "Unprocessable Entity" makes much more sense. My reasoning is that it's not that the server refuses to fulfill request, it's that the server can't fulfill the request.

REST HTTP status codes for failed validation or invalid duplicate - St...

http rest http-status-codes
Rectangle 27 33

Solution 2, return and handle 401 Unautorized status code

If an Ajax request is denied authorization, then usually you dont want to return an HTTP redirection to the login page, because your client-side code is not expecting that and may do something unwanted such as injecting the entire login page into the middle of whatever page the user is on. Instead, youll want to send back a more useful signal to the client-side code, perhaps in JSON format, to explain that the request was not authorized. You could implement this as follows:

You'd then get back a JSON object from the controller {'Error': 'NotAuthorized', 'LogonUrl': '...'} which you could then use to redirect the user.

And alternative response, if you're expecting HTML, could be to return a plain string, like NotAuthorized:<your_url> and check if the response matches this pattern.

As this has to be checked on every ajax request's success callback, this gets quite tedious. It would be nice to be able to catch this case globally. The best solution would be to return a 401 Unauthorized status code from the server and use jQuery's .ajaxError to catch it, but this is problematic on IIS/ASP.NET, since it's deadly committed to redirecting you to the login page if the response has this statuscode. As long as the <authentication> tag is present in web.config this redirection will happen [1] if you don't do something about it.

protected void Application_EndRequest()
{
    if (Context.Response.StatusCode == 302 && Context.Request.RequestContext.HttpContext.Request.IsAjaxRequest())
    {
        Context.Response.Clear();
        Context.Response.StatusCode = 401;
    }
}

(I'd love to hear it if anyone knows of any better methods to return a 401 status code.)

By doing this, you're preventing the default behaviour of redirecting to the logon page when the request is an ajax request. You can therefore use the default AuthorizeAttribute as it is, since Application_EndRequest takes care of the rest.

Now, in the jQuery code we'll use the .ajaxError function to catch the error. This is a global ajax event handler, meaning it will intercept every error made by any ajax call. It can be attached to any element - in my example I've just chosen body cause its always present

$("body").ajaxError(function(event, XMLHttpRequest, ajaxOptions, thrownError) {
    if (XMLHttpRequest.status == 401) {
        alert("unauthorized");
    }
});

This way you get your redirection logic centralized in one place, instead of having to check it on every damn ajax request success callback

This answer offers an alternative solution. It uses the same kind of global event handler, but skips the hacky bits. It adds a custom header to the page if you're not authenticated and the request is an ajax request, and checks for this header on each .ajaxComplete. Note that the method provided in the linked answer is unsecure, as it will return the original view with possibly sensitive content and rely on javascript to redirect the user away from it. With a bit of modification it's quite awesome as it doesn't require any hacks and the logic can be centralized to one callback function. The only downside as I can see is that it doens't reply with the semantically correct status code, as it's actually not 200 OK because you're 401 Unauthorized

EnhancedAuthorizationAttribute
public class EnhancedAuthorizeAttribute : AuthorizeAttribute
{
        protected override void HandleUnauthorizedRequest(AuthorizationContext context)
        {
            if (context.HttpContext.Request.IsAjaxRequest()) 
            {
                context.HttpContext.Response.AddHeader("REQUIRES_AUTH", "1");
                context.Result = new EmptyResult();
            }
            else
            {
                base.HandleUnauthorizedRequest(context);
            }
        }
    }
}

Now, every time an ajax request completes, you check for this header:

$('body').ajaxComplete(function(event,request,settings){
    if (request.getResponseHeader('REQUIRES_AUTH') === '1'){
        alert("unauthorized");
    };
});

+1, however, bear in mind that this will need to be handled in the success handler of the ajax request, as the response code will be 200. As stated in the HttpUnauthorizedResult class (mvc source code), FormsAuthenticationModule looks for 401 responses and instead redirects the user to the login page. This is why the answer provided in the question that @fynnbob mentioned is not correct. If you set a status code 401 in the Response, the client will not see that response code and hence it will not hit the ajax error handler.

Thanks for the responses. I'm actually using jQuery to load the partial (eg. $("#salescharts").load('/Sales/SalesByProduct?productId=12345');). I will try this approach and update the post when I'm done.

@uvita: Updated my answer with a hacky way to enable returning 401. @fynnbob Handling this with the .ajaxError function allows you to keep using .load ect and not be forced to use the lower level functions

And a third way :)

As of jQuery 1.8, the .ajaxComplete() method should only be attached to document.

jquery - A controller action which returns a partial view inserts the ...

jquery asp.net-mvc partial-views authentication authorize-attribute
Rectangle 27 8

Wrong. 401 is part of Hypertext Transfer Protocol (RFC 2616 Fielding, et al.), but not limited to HTTP authentication. Furthermore, it's the only status code indicating that the request requires user authentication.

302 & 200 codes could be used and is easier to implement in some scenarios, but not all. And if you want to obey the specs, 401 is the only correct answer there is.

And 403 is indeed the most wrong code to return. As you correctly stated...

Authorization will not help and the request SHOULD NOT be repeated.

So this is clearly not suitable to indicate that authorization is an option.

To add a little more info, lifting the confusion related to...

The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource.

If you think that's going to stop you from using a 401, you have to remember there's more:

"The field value consists of at least one challenge that indicates the authentication scheme(s) and parameters applicable to the Request-URI."

This "indicating the authentication scheme(s)" means you can opt-in for other auth-schemes!

The HTTP protocol (RFC 2616) defines a simple framework for access authentication schemes, but you don't HAVE to use THAT framework.

In other words: you're not bound to the usual WWW-Auth. You only just MUST indicate HOW your webapp does it's authorization and offer the according data in the header, that's all. According to the specs, using a 401, you can choose your own poison of authorization! And that's where your "webapp" can do what YOU want it to do when it comes to the 401 header and your authorization implementation.

Don't let the specs confuse you, thinking you HAVE to use the usual HTTP authentication scheme. You don't! The only thing the specs really enforce: you just HAVE/MUST identify your webapp's authentication scheme and pass on related parameters to enable the requesting party to start potential authorization attempts.

And if you're still unsure, I can put all this into a simple but understandable perspective: let's say you're going to invent a new authorization scheme tomorrow, then the specs allow you to use that too. If the specs would have restricted implementation of such newer authorization technology implementations, those specs would've been modified ages ago. The specs define standards, but they do not really limit the multitude of potential implementations.

The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource.

show an example of a WWW-Authentication header you would use with a 401 where an authentication cookie is needed?

rest - Correct http status code for resource which requires authorizat...

rest http-status-codes
Rectangle 27 8

Wrong. 401 is part of Hypertext Transfer Protocol (RFC 2616 Fielding, et al.), but not limited to HTTP authentication. Furthermore, it's the only status code indicating that the request requires user authentication.

302 & 200 codes could be used and is easier to implement in some scenarios, but not all. And if you want to obey the specs, 401 is the only correct answer there is.

And 403 is indeed the most wrong code to return. As you correctly stated...

Authorization will not help and the request SHOULD NOT be repeated.

So this is clearly not suitable to indicate that authorization is an option.

To add a little more info, lifting the confusion related to...

The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource.

If you think that's going to stop you from using a 401, you have to remember there's more:

"The field value consists of at least one challenge that indicates the authentication scheme(s) and parameters applicable to the Request-URI."

This "indicating the authentication scheme(s)" means you can opt-in for other auth-schemes!

The HTTP protocol (RFC 2616) defines a simple framework for access authentication schemes, but you don't HAVE to use THAT framework.

In other words: you're not bound to the usual WWW-Auth. You only just MUST indicate HOW your webapp does it's authorization and offer the according data in the header, that's all. According to the specs, using a 401, you can choose your own poison of authorization! And that's where your "webapp" can do what YOU want it to do when it comes to the 401 header and your authorization implementation.

Don't let the specs confuse you, thinking you HAVE to use the usual HTTP authentication scheme. You don't! The only thing the specs really enforce: you just HAVE/MUST identify your webapp's authentication scheme and pass on related parameters to enable the requesting party to start potential authorization attempts.

And if you're still unsure, I can put all this into a simple but understandable perspective: let's say you're going to invent a new authorization scheme tomorrow, then the specs allow you to use that too. If the specs would have restricted implementation of such newer authorization technology implementations, those specs would've been modified ages ago. The specs define standards, but they do not really limit the multitude of potential implementations.

The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource.

show an example of a WWW-Authentication header you would use with a 401 where an authentication cookie is needed?

rest - Correct http status code for resource which requires authorizat...

rest http-status-codes
Rectangle 27 45

This error happens because the server sends a 401 (Unauthorized) but does not give a WWW-Authenticate header which is a hint to the client what to do next. The WWW-Authenticate header tells the client, which kind of authentication is needed (either Basic or Digest). This is probably not very useful in headless http clients, but that's how the HTTP 1.1 RFC is defined. The error occurs because the lib tries to parse the WWW-Authenticate header but can't.

(...)The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource.(...)

Possible solutions if you can change the server:

  • Add a fake "WWW-Authenticate" header like: WWW-Authenticate: Basic realm="fake". This is a mere workaround not a solution, but it should work and the http client is satisfied (see here a discussion of what you can put in the header). But beware that some http clients may automatically retry the request resulting in multiple requests (e.g. increments the wrong login count too often). This was observed with the iOS http client.
  • As proposed by loudvchar in this blog to avoid automatic reactions to the challenge like a pop-up login form in a browser, you can use a non-standard authentication method like so: WWW-Authenticate: xBasic realm="fake". The important point is that the realm has to be included.
  • Use HTTP status code 403 instead of 401. It's semantic is not the same and usually when working with login 401 is a correct response (see here for a detailed discussion) but the safer solution in terms of compatibility.

Possible solutions if you can't change the server:

  • As @ErikZ wrote in his post you could use a try&catch HttpURLConnection connection = ...; try { // Will throw IOException if server responds with 401. connection.getResponseCode(); } catch (IOException e) { // Will return 401, because now connection has the correct internal state. int responsecode = connection.getResponseCode(); }

Cool man, I swear I saw a different behavior, anyway just tested what you are saying and is correct +1...

I'm having this problem on one Android device but not another, I guess some OEMs overwrite the HttpUrlConnection class? Either way, this fix worked.

You are a god among men.

android - java.io.IOException : No authentication challenges found - S...

java android authentication httpurlconnection ioexception
Rectangle 27 129

Can someone give me a step by step description of how cookie based authentication works? I've never done anything involving either authentication or cookies. What does the browser need to do? What does the server need to do? In what order? How do we keep things secure?

Before anything else, the user has to sign up. The client posts a HTTP request to the server containing his/her username and password.

The server receives this request and hashes the password before storing the username and password in your database. This way, if someone gains access to your database they won't see your users' actual passwords.

Now your user logs in. He/she provides their username/password and again, this is posted as a HTTP request to the server.

The server looks up the username in the database, hashes the supplied login password, and compares it to the previously hashed password in the database. If it doesn't check out, we may deny them access by sending a 401 status code and ending the request.

If everything checks out, we're going to create an access token, which uniquely identifies the user's session. Still in the server, we do two things with the access token:

  • Store it in the database associated with that user

Henceforth, the cookies will be attached to every request (and response) made between the client and server.

Back on the client side, we are now logged in. Every time the client makes a request for a page that requires authorization (i.e. they need to be logged in), the server obtains the access token from the cookie and checks it against the one in the database associated with that user. If it checks out, access is granted.

This should get you started. Be sure to clear the cookies upon logout!

Thanks for the description. I just wonder how does access token provides security? Can an attacker if steals the cookie, pose as an authenticated logged in user? Or that is protected by SSL?

@Richeek SSL secures interception during requests/responses, but an attacker might access your cookies at the endpoints (e.g. your browser). Theoretically, they could then pose as a logged in user until the cookie expires. I say theoretically because the implementation above doesnt handle that. In the above implementation, the attacker will have access until the access token in your database is updated (i.e. next login).

You might invalidate the access token upon expiry yourself, perhaps with an expiration date in your database. Or, you could consider using JSON Web Tokens (JWT), which are like access tokens, but can handle token expiry among other things. More on JWT here. An attacker will still have access to your account for brief periods of time if they have your access token/JWT, so you should also secure your endpoints.

How does cookie based authentication work? - Stack Overflow

authentication cookies browser
Rectangle 27 45

This error happens because the server sends a 401 (Unauthorized) but does not give a WWW-Authenticate header which is a hint to the client what to do next. The WWW-Authenticate header tells the client, which kind of authentication is needed (either Basic or Digest). This is probably not very useful in headless http clients, but that's how the HTTP 1.1 RFC is defined. The error occurs because the lib tries to parse the WWW-Authenticate header but can't.

(...)The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource.(...)

Possible solutions if you can change the server:

  • Add a fake "WWW-Authenticate" header like: WWW-Authenticate: Basic realm="fake". This is a mere workaround not a solution, but it should work and the http client is satisfied (see here a discussion of what you can put in the header). But beware that some http clients may automatically retry the request resulting in multiple requests (e.g. increments the wrong login count too often). This was observed with the iOS http client.
  • As proposed by loudvchar in this blog to avoid automatic reactions to the challenge like a pop-up login form in a browser, you can use a non-standard authentication method like so: WWW-Authenticate: xBasic realm="fake". The important point is that the realm has to be included.
  • Use HTTP status code 403 instead of 401. It's semantic is not the same and usually when working with login 401 is a correct response (see here for a detailed discussion) but the safer solution in terms of compatibility.

Possible solutions if you can't change the server:

  • As @ErikZ wrote in his post you could use a try&catch HttpURLConnection connection = ...; try { // Will throw IOException if server responds with 401. connection.getResponseCode(); } catch (IOException e) { // Will return 401, because now connection has the correct internal state. int responsecode = connection.getResponseCode(); }

Cool man, I swear I saw a different behavior, anyway just tested what you are saying and is correct +1...

I'm having this problem on one Android device but not another, I guess some OEMs overwrite the HttpUrlConnection class? Either way, this fix worked.

You are a god among men.

android - java.io.IOException : No authentication challenges found - S...

java android authentication httpurlconnection ioexception
Rectangle 27 5

Basically you return your own HTTP status code (e.g. 418) in your code. In my case a WCF data service.

throw new DataServiceException(418, "401 Unauthorized");

Then use a HTTP module to handle it at the EndRequest event to rewrite the code back to 401.

HttpApplication app = (HttpApplication)sender;
if (app.Context.Response.StatusCode == 418)
{
    app.Context.Response.StatusCode = 401;
}

The browser / client will receive the correct content and status code, it works great for me :)

If you are interested to learn more about HTTP status code 418 see this question & answer.

Great! It works like I want it to work :) instead adding dedicated http module I used "global.asax" event EndRequest. It is possible to hook on this event overriding "Init" method

this just returns the IIS 401 error page for me

Thanks for mentioning using your own status codes: Since I was only looking to return 401 for a single page that tested authentication via AJAX call, I was able to change the "fail" Response.StatusCode on that page to 418 to avoid all the other workarounds! IIS7 complains, but no human would need to visit that page.

asp.net - Forms authentication: disable redirect to the login page - S...

asp.net forms-authentication
Rectangle 27 8

This error happens because the server sends a 401 (Unauthorized) but does not give a "WWW-Authenticate" which is a hint for the client what to do next. The "WWW-Authenticate" Header tells the client which kind of authentication is needed (either Basic or Digest). This is usually not very useful in headless http clients, but that's how the standard is defined. The error occurs because the lib tries to parse the "WWW-Authenticate" header but can't.

Possible solutions if you can change the server:

  • Add a fake "WWW-Authenticate" header like: WWW-Authenticate: Basic realm="fake". This is a mere workaround not a solution, but it should work and the http client is satisfied.
  • Use HTTP status code 403 instead of 401. It's semantic is not the same and usually when working with login 401 is a correct response (see here for a detailed discussion) but its close enough.

Possible solutions if you can't change the server:

As @ErikZ wrote in his post you could use a try&catch

HttpURLConnection connection = ...;
try {
    // Will throw IOException if server responds with 401.
    connection.getResponseCode(); 
} catch (IOException e) {
    // Will return 401, because now connection has the correct internal state.
    int responsecode = connection.getResponseCode(); 
}

I'm trying to send a header with Digest authentication, but can't figured out how to do it (still searching for an answer). Do you have any sample on how to do a Digest (or even basic) authentication in Android-Volley?

Basic and Digest is just putting a header that looks like this "Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" in Basic and more complicated in digest - this is not special to volley, you just put set headers (google on how to do that in volley)

I'm sorry I asked this question so long ago I don't even remember what it relates to, plus that legacy project has been shut down. I'll upvote your answer for effort you've put in, but have no way of checking it's right so won't select it as the answer I'm afraid.

Fair enough. Ill leave it since it took me quite a while to understand the problem - learning REST/HTTP spec isn't sometimes as straight forward as you think :)

how to add WWW-Authenticate header in the server response

android - volley error No authentication challenges found - Stack Over...

android authentication android-volley
Rectangle 27 6

This is a tricky question, largely because the most well-established HTTP clients used by people are browsers. According to the RFC, the WWW-Authenticate header can contain anything. Basic and digest authentication are just two examples of further standardised challenge/response mechanisms. You can simply specify a challenge like html-form id=foo and return the 401 along with an HTML form. Also, recall from the spec that multiple challenges can be specified within the same WWW-Authenticate header, but I don't have any experience testing browsers extensively with different schemes.

rest - Correct HTTP status code for login form? - Stack Overflow

http rest http-status-codes
Rectangle 27 1

I would not make access and refresh tokens interchangeable: Use Access-Tokens to access protected resources and use Refresh-Token to fetch new Access-Token from a special end-point. OpenID Connect works this way.

You would have one HTTP request more but HTTP codes would not be a problem and, in my opinion, you would get a cleaner code.

HTTP status if re-authentication is required - Stack Overflow

http authentication access-token http-status-codes http-status-code-401
Rectangle 27 217

You have to be careful, server responses in the range of 4xx and 5xx throw a WebException. You need to catch it, and then get status code from a WebException object:

try
{
    wResp = (HttpWebResponse)wReq.GetResponse();
    wRespStatusCode = wResp.StatusCode;
}
catch (WebException we)
{
    wRespStatusCode = ((HttpWebResponse)we.Response).StatusCode;
}

I'm glad you mentioned the 4xx and 5xx because I was having issues with a program not acting properly. I should point out though that the current .NET framework will notify you of any uncaught exceptions so this is also a no-brainer.

As a bonus, one used to be able to decorate a method with [DebuggerNonUserCode] and the Debugger would not stop in that method when an exception is thrown. In this manner poorly designed exceptions could be wrapped and ignored. But now a registry setting is required

c# - Getting Http Status code number (200, 301, 404, etc.) from HttpWe...

c# .net http httpwebrequest
Rectangle 27 229

Brief and Terse

Something the other answers are missing is that it must be understood that Authentication and Authorization in the context of RFC 2616 refers ONLY to the HTTP Authentication protocol of RFC 2617. Authentication by schemes outside of RFC2617 are not supported in HTTP status codes and are not considered when deciding whether to use 401 or 403..

Unauthorized indicates that the client is not RFC2617 authenticated and the server is initiating the authentication process. Forbidden indicates either that the client is RFC2617 authenticated and does not have authorization or that the server does not support RFC2617 for the requested resource.

Meaning if you have your own roll-your-own login process and never use HTTP Authentication, 403 is always the proper response and 401 should never be used.

The request requires user authentication. The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource. The client MAY repeat the request with a suitable Authorization header field (section 14.8).

and

10.4.4 403 Forbidden The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated.

The first thing to keep in mind is that "Authentication" and "Authorization" in the context of this document refer specifically to the HTTP Authentication protocols from RFC 2617. They do not refer to any roll-your-own authentication protocols you may have created using login pages, etc. I will use "login" to refer to authentication and authorization by methods other than RFC2617

So the real difference is not what the problem is or even if there is a solution. The difference is what the server expects the client to do next.

401 indicates that the resource can not be provided, but the server is REQUESTING that the client log in through HTTP Authentication and has sent reply headers to initiate the process. Possibly there are authorizations that will permit access to the resource, possibly there are not, but lets give it a try and see what happens.

403 indicates that the resource can not be provided and there is, for the current user, no way to solve this through RFC2617 and no point in trying. This may be because it is known that no level of authentication is sufficient (for instance because of an IP blacklist), but it may be because the user is already authenticated and does not have authority. The RFC2617 model is one-user, one-credentials so the case where the user may have a second set of credentials that could be authorized may be ignored. It neither suggests nor implies that some sort of login page or other non-RFC2617 authentication protocol may or may not help - that is outside the RFC2616 standards and definition.

So what should we do when the user requests a page that requires non-http authentication? Send status code 403?

This is important: "if you have your own roll-your-own login process and never use HTTP Authentication, 403 is always the proper response and 401 should never be used."

Doesn't RFC7235 provide for "roll-your-own" or alternate auth challenges? Why can't my app's login flow present its challenge in the form of a WWW-Authenticate header? Even if a browser doesn't support it, my React app can...

403 Forbidden vs 401 Unauthorized HTTP responses - Stack Overflow

http-headers http-status-code-403 http-status-codes http-status-code-401 http-response-codes
Rectangle 27 94

What are you expecting? The default Tomcat homepage? If so, you'll need to configure Eclipse to take control over from Tomcat.

Doubleclick the Tomcat server entry in the Servers tab, you'll get the server configuration. At the left column, under Server Locations, select Use Tomcat installation (note, when it is grayed out, read the section leading text! ;) ). This way Eclipse will take full control over Tomcat, this way you'll also be able to access the default Tomcat homepage with the Tomcat Manager when running from inside Eclipse. I only don't see how that's useful while developing using Eclipse.

The port number is not the problem. You would otherwise have gotten an exception in Tomcat's startup log and the browser would show a browser-specific "Connection timed out" error page (and thus not a Tomcat-specific error page which would impossibly be served when Tomcat was not up and running!)

If the section is grayed out, make sure the tomcat does not have any projects configured. If so delete it and the grayed portion will be active and save the configurations and it works fine

@Laavaa: that's also very clearly mentioned in the section... "Server must be published with no modules present to make changes" :)

Tomcat server > right click > general {notice the value of location} > switch location {value of location changes} > ok.
workspace metadata option

Still does not work. I get the 404 error.

In additional to the steps mentioned here, I also had to start and stop the server before grayed portion would become active.

eclipse - HTTP Status 404 - The requested resource (/) is not availabl...

eclipse jsp tomcat http-status-code-404
Rectangle 27 14

I've written an AngularJS module for UserApp that supports protected/public routes, rerouting on login/logout, heartbeats for status checks, stores the session token in a cookie, events, etc.

  • Modify the module and attach it to your own API, or
  • Use the module together with UserApp (a cloud-based user management API)

If you use UserApp, you won't have to write any server-side code for the user stuff (more than validating a token). Take the course on Codecademy to try it out.

  • How to specify which routes that should be public, and which route that is the login form: $routeProvider.when('/login', {templateUrl: 'partials/login.html', public: true, login: true}); $routeProvider.when('/signup', {templateUrl: 'partials/signup.html', public: true}); $routeProvider.when('/home', {templateUrl: 'partials/home.html'}); The .otherwise() route should be set to where you want your users to be redirected after login. Example: $routeProvider.otherwise({redirectTo: '/home'});
  • Login form with error handling: <form ua-login ua-error="error-msg"> <input name="login" placeholder="Username"><br> <input name="password" placeholder="Password" type="password"><br> <button type="submit">Log in</button> <p id="error-msg"></p> </form>
  • Signup form with error handling: <form ua-signup ua-error="error-msg"> <input name="first_name" placeholder="Your name"><br> <input name="login" ua-is-email placeholder="Email"><br> <input name="password" placeholder="Password" type="password"><br> <button type="submit">Create account</button> <p id="error-msg"></p> </form>
<a href="#" ua-logout>Log Out</a>

(Ends the session and redirects to the login route)

User properties are accessed using the user service, e.g: user.current.email

<span>{{ user.email }}</span>

Hide elements that should only be visible when logged in:

<div ng-show="user.authorized">Welcome {{ user.first_name }}!</div>
  • Show an element based on permissions: <div ua-has-permission="admin">You are an admin</div>

And to authenticate to your back-end services, just use user.token() to get the session token and send it with the AJAX request. At the back-end, use the UserApp API (if you use UserApp) to check if the token is valid or not.

If you need any help, just let me know!

javascript - AngularJS: Basic example to use authentication in Single ...

javascript angularjs authentication login