102

A similar question is posted here: What's an appropriate HTTP status code to return by a REST API service for a validation failure?

The answer in the thread above states that "For instance if the URI is supposed to have an ISO-8601 date and you find that it's in the wrong format or refers to February 31st, then you would return an HTTP 400. Ditto if you expect well-formed XML in an entity body and it fails to parse."

However, what happens if the user submitted correctly formatted data? By this I mean, the user submitted a plain alphabetical string / text for the username and password (which is perfectly valid for my application). The only issue is that the password did not match with the username. In this case, 400 will be incorrect because it is perfectly valid syntax and well-formed.

A 401 would be incorrect (as suggested here: Which HTTP status code to say username or password were incorrect?) because the user is not trying to access any page, he is simply trying to login and entered data which does not match.

If you look back at the first post I linked to, the second answer states that 422 is the correct response (and it looks correct to me), however, I am using Django Rest Framework and 422 is not part of the status codes (a list of the status codes which are part of DRF can be found here: http://www.django-rest-framework.org/api-guide/status-codes/#client-error-4xx)

404 also doesn't look right because the data is successfully accepted and not refused.

With that said, what is the real correct response which should be used?

Community
  • 1
  • 1
SilentDev
  • 15,207
  • 26
  • 87
  • 180

4 Answers4

143

The correct HTTP code would actually be 401. From the RFC:

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 (Section 4.1) 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 (Section 4.2).

Community
  • 1
  • 1
sjagr
  • 14,280
  • 4
  • 37
  • 63
  • 1
    oh you're right, 401 is what I should be using. Wow, can't believe I missed the second part of the explanation. Thanks. I'll mark this question as correct in 8 minutes when it allows me to. – SilentDev Sep 24 '15 at 03:03
  • From the very part you are quoting, a 401 response indicates that the request has **not been applied**. Therefore, no login **attempt** was even made, because authorization is needed at a lower level first. This can usually happen when several layers of security are nested, and is a valid response to indicate the requirement to auth with an outer layer before attempting to auth with an inner layer. – spectras May 11 '17 at 08:24
  • @spectras "the request has not been applied because it **lacks valid authentication credentials for the target resource**" - however I'm pointing to the second part where the request did include authentication credentials and were refused, a separate case and _section_ altogether. If you want to split hairs over this though, perhaps suggest a better status code instead. – sjagr May 11 '17 at 15:16
  • 3
    @sjagr> actually, I commented because I was linked your answer on my take on the same question, here: http://stackoverflow.com/a/32897804/3212865 . The main point being the question mixes up different layers of communication and the most orthogonal response would actually be 200, meaning _“the request was processed successfully and a login attempt was made accordingly, find the result in the response's content”_. Attempting to express an application-level error in a transport-level status code is a design mistake. – spectras May 11 '17 at 19:21
  • 9
    I think this answer is wrong. The requirement for an accompanying `WWW-Authenticate` implies 401 is for prompting for authentication via HTTP Basic or similar. For failed logins (in a typical cookie-based login scenario), you should use 403, as explained by this answer: https://webmasters.stackexchange.com/questions/24443/should-i-return-a-http-401-status-code-on-an-html-based-login-form – callum Sep 27 '18 at 14:24
  • 2
    This seems to be subject to some interpretation depending on how literally some statements are taken. My understanding is that the request lacks *valid* authentication credentials, not that it _lacks credentials at all_. Since the second portion still mentions that the request could have included credentials in the first place, I'm of the opinion that the 401 status is correct. – sjagr Aug 26 '19 at 13:48
  • 1
    @sjagr I think it lacks credentials at all, as credentials wrt a request exist in the headers. Sending 401 implies you don't have permission to attempt login as @spectras suggested. A separation of concerns exists between data transfer and application logic, so sending anything other than a `2xx` status for a successfully produced failed login response is unnecessary, overcomplicated, and inconsistent with other things your web server might do. – KernelDeimos May 02 '21 at 18:17
10

401 - Unauthorized

403 - Forbidden

http://www.buggybread.com/2012/11/http-error-codes-401-access-denied-403.html

Andy Mercer
  • 5,605
  • 5
  • 40
  • 80
Tony Arnold
  • 579
  • 1
  • 6
  • 15
1

Use the appropriate status code in 2xx for a successfully handled login request with the wrong password.

Before asking "what is the correct HTTP status code", it's important to consider this question: "Should success or failure of login be reflected in the HTTP status code of the response?"

In @sjagr's answer the first part of this section is highlighted. I'm going to highlight the second part and explain why:

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 (Section 4.2).

This refers to an Authorization header, rather than a request body containing login credentials. The phrasing of the first part, unfortunately, could be misinterpreted to refer to a request body containing login information. This ambiguity can be resolved by considering separation of concerns; (https://en.wikipedia.org/wiki/Separation_of_concerns) the server's response header should not depend on the differences of two valid request bodies, with the exception of when it causes an internal server error, otherwise the concerns of data transfer and appliction login begin to creep into each other.

I would use HTTP response 2xx for a valid login request, where the client has permission to attempt a login, that is handled successfully with a response indicating success or failure.

I also like the way @spectras expressed this in the comments:

Attempting to express an application-level error in a transport-level status code is a design mistake.

KernelDeimos
  • 111
  • 1
  • 6
-21

I think that it will be good to set response status code 200. To prevent wordlist attack. In huge massive cybercriminal could not identify which request and responses are right )))

Levon
  • 197
  • 3
  • 9
  • 4
    This is what rate limiting and timeouts/blacklisting are for. – T1960CT Mar 10 '20 at 17:39
  • 7
    A "cybercriminal" can parse the body of the response instead. – dionyziz May 13 '20 at 19:25
  • 1
    I think **200** is correct but not for the reasons of this answer. 200 means the request was processed, not that the login was successful. The response body you can specify the reason: "wrong password", "user not found", "user blocked". 201 can be the response when the login success. A session is usually created and stored somewhere. The response usually returns a token (maybe a cookie). 401/403 indicates the request cannot be processed, no authorization to make that call. 404 for failed login? How you distinguish it to a "real" 404 (/loggging?user=aaa&paswd=bbb) – Alex 75 Jan 31 '21 at 20:12