Does incorrectly returning an HTTP status code break the protocol? - http

For instance, if a request failed due to no authorization, clients expect a 401. However, if a server returns a 200 but with a message indicating failure to authenticate, does this technically go against the HTTP protocol? From my research it appears the answer is "Yes, it does. Failures should at the very least be 4xx but ideally more descriptive i.e. 401", but I'm curious if such a variance in status code actually breaks protocol or if they are merely strong suggestions.

RFC 9110 HTTP Semantics tells us that:
A client cannot begin using an upgraded protocol on the connection until it has completely sent the request message (i.e., the client can't change the protocol it is sending in the middle of a message). If a server receives both an Upgrade and an Expect header field with the "100-continue" expectation (Section 10.1.1), the server MUST send a 100 (Continue) response before sending a 101 (Switching Protocols) response
In the same RFC:
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.
And finally RFC 2119:
MUST This word, or the terms "REQUIRED" or "SHALL", mean that the
definition is an absolute requirement of the specification.
Therefore, if the server wants to support HTTP/1.1, he can't ignore certain of the protocol's strict requirements, such returning a specified status code in certain cases.
In your example, the client doesn't have to wait for a response with 401 status code because the server generates a 401 when it wants to. If the server believes the client should authenticate, it will send a 401, but it can also send a 403 instead. For instance, on servers that use Session authentication (authentication occurs through cookies and the request body), a 401 is never sent.
However, if the server decides to send a 401, RFC 9110 requires it to include the "WWW-Authenticate" header.
A server generating a 401 (Unauthorized) response MUST send a WWW-Authenticate header field containing at least one challenge. A server MAY generate a WWW-Authenticate header field in other response messages to indicate that supplying credentials (or different credentials) might affect the response.

Related

What's the appropriate HTTP status code when the request is missing a required cookie?

I have an API endpoint and the request should have a cookie (not authentication). What would be the correct HTTP status code to return if it isn't present?
I would assume a 400 Bad Request would be the best.
No much details are provided in your question, but I guess 400 (Bad Request) is a good option:
6.5.1. 400 Bad Request
The 400 (Bad Request) status code indicates that the server cannot or
will not process the request due to something that is perceived to be
a client error (e.g., malformed request syntax, invalid request
message framing, or deceptive request routing).
However, depending on your requirements, you also could consider the 422 (Unprocessable Entity) status code, defined in the WebDAV specification, which is just an extension of the HTTP protocol:
11.2. 422 Unprocessable Entity
The 422 (Unprocessable Entity) status code means the server
understands the content type of the request entity (hence a
415 (Unsupported Media Type) status code is inappropriate), and the
syntax of the request entity is correct (thus a 400 (Bad Request)
status code is inappropriate) but was unable to process the contained
instructions. For example, this error condition may occur if an XML
request body contains well-formed (i.e., syntactically correct), but
semantically erroneous, XML instructions.
Just remember providing a good description in the response payload explaining what's missing in the request.
I would consider a 403 forbidden status code for this situation - where everything else is fine but the request is missing a cookie. To copy its details from the linked reference:
The server understood the request but refuses to authorize it.
If authentication credentials were provided in the request, the server considers them insufficient to grant access
Status 401 unauthorized is for when the request lacks authentication credentials. But 401 also requires the response to contain a WWW-Authenticate header field. Based on the question, the request should have a cookie but doesn't, and it isn't a matter of authentication.
Status 400 is when the client request was erroneous, which might be a bit misleading for the scenario the OP describes.
Status 422 might be appropriate, but I think, a bit too generic since it means something on the lines of everything was okay, but the server is unable to process the request.

HTTP status for "email not verified"

I have seen the list of all HTTP status codes.
However to me it looks like there is no code for "email not verified" (used for authentication/authorization).
Did you ever had the same "problem"? What HTTP status code did you use?
I guess it should be a code starting with a 4 as it's a "client error".
The 4xx class of status code is intended for situations in which the client seems to have erred:
6.5. Client Error 4xx
The 4xx (Client Error) class of status code indicates that the client
seems to have erred. Except when responding to a HEAD request, the
server SHOULD send a representation containing an explanation of the
error situation, and whether it is a temporary or permanent
condition. These status codes are applicable to any request method.
User agents SHOULD display any included representation to the user.
For authentication and authorization, 401 and 403 are the proper status codes to be used, respectively. Regardless of the status code, you should always describe that reason of the error in the response payload.
401 Unauthorized
Use this status code for problems with HTTP authentication, that is, invalid credentials.
3.1. 401 Unauthorized
The 401 (Unauthorized) status code indicates that the request has not
been applied because it lacks valid authentication credentials for
the target resource. The server generating a 401 response MUST send
a WWW-Authenticate header field containing at least one
challenge applicable to the target resource.
If the request included authentication credentials, then the 401
response indicates that authorization has been refused for those
credentials. The user agent MAY repeat the request with a new or
replaced Authorization header field. If the 401
response contains the same challenge as the prior response, and the
user agent has already attempted authentication at least once, then
the user agent SHOULD present the enclosed representation to the
user, since it usually contains relevant diagnostic information.
403 Forbidden
Use this status code for problems with authorization, that is, the credentials are valid but they are insufficient to grant access.
6.5.3. 403 Forbidden
The 403 (Forbidden) status code indicates that the server understood
the request but refuses to authorize it. A server that wishes to
make public why the request has been forbidden can describe that
reason in the response payload (if any).
If authentication credentials were provided in the request, the
server considers them insufficient to grant access. The client
SHOULD NOT automatically repeat the request with the same
credentials. The client MAY repeat the request with new or different
credentials. However, a request might be forbidden for reasons
unrelated to the credentials. [...]
While CodeCaster has provided a very definitive answer as a comment, that which is correct is sometimes not appropriate.
Firstly, you'll see there is no mention of email addresses in the specs. Similarly there is no mention of shoe sizes, model railway gauges, breeds of dogs nor many other things. It is not relevant to HTTP. This is just a data item.
You seem to have some state associated with this data item which you use for authentication purposes - but don't provide any explanation of that state nor how it is applied. I assume that you mean that the "not verified" state means that the only association between the data item and the user interacting with your site is an assertion of the user. And further that you do not allow the user to authenticate with this as a token.
It may seem I'm being pedantic here - but there are other, valid interpretations of "email not verified". You should have provided more information in your question.
There's another gap in your story: which request are we taking about here? Again, I'll take the liberty of assuming that the request is an attempt to authenticate.
In this case, there is nothing intrinsically wrong with the request. There is nothing intrinsically wrong with the client. There is nothing intrinsically wrong at the server. Not permitting the user to authenticate is a policy decision based on the data.
Another critical bit of information missing from your question is what is actually making the request. If its a form sent by a browser, then returning anything other than a 200 OK (or 204, or a redirect to a 200) to MSIE will, by default, cause the browser to display an internal message and not the content you send.
OTOH if the client is an application running on the users device, or an Ajax request, then you control the API and can define your own semantics. If you want to return a 692 status code to represent this condition, then you can return a 692 error code. You can even inject your own headers in the response (by convention these should begin with 'X-').
In the defined state the authentication fails. But returning a 401 response will prompt a browser to attempt HTTP authentication - which doesn't address the issue.
IMHO, the nearest existing code is 403 or 422. But based on the information you've supplied I can't say if thats what you should be using.

Determine whether a Basic Authentication login was successful

How does an HTTP client definitively determine whether a login was successful when using Basic Authentication? I've always thought that it was simple - look at the response code:
200 = Successful
401 = Unsuccessful
This is not correct. If you read RFC 2617 it says:
If the origin server does not wish to accept the credentials sent with
a request, it SHOULD return a 401 (Unauthorized) response. The
response MUST include a WWW-Authenticate header field containing at
least one (possibly new) challenge applicable to the requested
resource.
The word SHOULD is tricky, and in fact I've seen devices that do not return a 401 on login failure. This would suggest:
WWW-Authenticate does not exist = Successful
WWW-Authenticate exists = Unsuccessful
This is also incorrect. I'm playing with a TP-LINK router that provides the following headers:
- Server : Router Webserver
- Connection : close
- Content-Type : text/html
- WWW-Authenticate : Basic realm="TP-LINK Wireless N Router WR841N"
The response code is 200.
Here we have a 200 with a WWW-Authenticate!!!!!
Given all of this, what is the DEFINITIVE way to determine whether a BA login was successful?
RFC 7235 obsoletes RFC 2617 and one of the corrections it brings is to point out that, SHOULD is to be interpreted as per RFC 2119. (This was perhaps omitted because it is pointed out in RFC 2616, which goes hand-in-hand with 2617):
SHOULD This word, or the adjective "RECOMMENDED", mean that there
may exist valid reasons in particular circumstances to ignore a
particular item, but the full implications must be understood and
carefully weighed before choosing a different course.
So, it's not just a matter of "well, you should do that, but we understand if you don't" as should means colloquially, but rather "you must do this, unless you have an extremely good reason that you can clearly state".
If a server has a very good reason for not sending a 401, it's most likely because it is sending some other error code (e.g. 404 to pretend the resource doesn't exist unless you've successfully authenticated). The wisdom of sending anything other than 401 is perhaps questionable, but the only reason to send 200 is because you want to indicate that the response is successful. Really, while the should does allow something other than 401, it really doesn't allow 200.
Including WWW-Authenticate on the other hand, definitely doesn't mean the authentication wasn't successful. It's allowed at any time, and with other schemes apart from Basic can be necessary on successful requests (to allow a nonce-count to increment, for example).
In short you've got three possible states: Success, Authentication Error, Some Other Error. The should allows for the last of those. If you get a 200 then you were successful (or well, the server is behaving wrong, but that always applies anyway).
The 200 status is what counts. That the server keeps including WWW-Authenticate simply is a bug.
And yes, I tested this, I happen to have the same router over here.

What HTTP status code use when the required header is not specified?

If the user sends request to the server and the link requires specific custom headers to be set in order to work. In this case the error code should be 400, 403 or 422 ?
The HTTP specification requires any client to treat the response as 400 by default if it does not understand the specific meaning of the final two digits. So you must always design with the assumption that some clients will treat the response as 400.
If you can find a 4xx status code whose special extra handling works better for your application, then use it. When the client understands enough to do that extra handling you are slightly better off than if you had sent the default status.
The currently registered status codes which seem to match your servers meaning are:
403 Forbidden - this is about server refusing the request until it is somehow changed. Preferrably with the reason stated in the response body.
406 Not Acceptible - this is more specifically about values in the request headers not being right. Most commonly used for the Accept: header values.
412 Precondition Failed - this is about the problems with headers involved with negotiating which response body would be sent. Most commonly used for the If-* header values.
The 403 seems to be most accurate for when a server refused to deliver anything unless the custom headers is sent.

Should HTTP Client parse HTTP Headers in response with the error 404 Not Found

I cannot find any RFC or Standard of HTTP client behavior in case it gets HTTP response with an error 4xx. I know the 401, 407 are the examples when the HTTP headers are parsed, but...
I have the concrete problem for OPTIONS method (HTTP1.1). The server responses 401 Unauthorized, so client tries to authenticate and re-sends the request with an authentication. After that the response has the error 404 Not Found and HTTP header is filled with Set-Cookie HTTP Header. The client use Apache Java HTTPClient/HTTPComponents, which ignores HTTP headers in case of an error in the response.
Should this HTTP Header be accepted by the client? I believe it should not be, but I cannot find the supportive quotation in the RFC.
RFC 2616 does not specify that any headers should be ignored, not for 404 responses and not for 4xx responses in general either.
RFC 6265 allows clients to ignore Set-Cookie headers, but does not specify situations where that might happen; a single example is given, that does not cover your case:
the user agent might wish to block responses to "third-party" requests
from setting cookies
In your case, since your server seems to use HTTP basic access authentication, it does not seem to concern the Set-Cookie header. In HTTP basic authentication, the Authorization header is sent by the client with every request, so there should be no need to keep state in a cookie.
It is not clear from your question if you have a very specific HTTP server that you're talking to, or if you are implementing a general HTTP client that is supposed to work with whatever server you throw it at. If you have such a specific case that the HTTP server you work with sends state with 404 responses, and you're required to honor that state in order to communicate with the server, and you have no control over the server, then it does not matter what the standard says; you will honor the state sent, or you will not be able to talk to the server.
If, on the other hand, you're implementing a general client and need it to work regardless of the remote server, then your best bet is to stick to RFC 1958:
Be strict when sending and tolerant when receiving.
Implementations must follow specifications precisely when sending to
the network, and tolerate faulty input from the network. When in
doubt, discard faulty input silently, without returning an error
message unless this is required by the specification.
Which, to me, would mean that you should honor the full response received, regardless of the status code, unless you have an objective reason making it impossible for you to do so. I don't see a reason to ignore the state, even if it violates the standard (or in this case, your personal perception of the standard, since it does not say anything about accepting or ignoring the state).
Update: RFC 2617 (HTTP Authentication) states:
A client SHOULD assume that all paths at or deeper than the depth of
the last symbolic element in the path field of the Request-URI also
are within the protection space specified by the Basic realm value of
the current challenge. A client MAY preemptively send the
corresponding Authorization header with requests for resources in
that space without receipt of another challenge from the server.
It is highly inconsistent if the server expects HTTP authentication for one URL, but does not honor it for URLs beneath it, requiring a separate cookie-based authentication for them. If anything should be changed in your server implementation, it should be to harmonize the authentication scheme for all resources.

Resources