ChatGPT解决这个技术问题 Extra ChatGPT

What's the appropriate HTTP status code to return if a user tries logging in with an incorrect username / password, but correct format?

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?


C
Community

If you are strictly using the HTTP authentication framework provided by RFC 7235 for your REST API, 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).

Your REST API should employ an authentication scheme of some sort in order to return a valid 401 response to your client.

Another pertinent section from RFC 7235, page 4:

Upon receipt of a request for a protected resource that omits credentials, contains invalid credentials (e.g., a bad password) or partial credentials (e.g., when the authentication scheme requires more than one round trip), an origin server SHOULD send a 401 (Unauthorized) response that contains a WWW-Authenticate header field with at least one (possibly new) challenge applicable to the requested resource.

A higher-level response, such as a rendered login page for a visual user (redirected from a protected resource via 302), would be better served with the 200 status code (per @KernelDeimos' answer, for example). Since login pages are typically their own resource (e.g. /login?redirect=original-resource), the unauthenticated user is still authorized to see this page, even if they provide an incorrect username/password. Then, you redirect the authenticated user back to the resource, at which point would show 200 if allowed, or 403 if the user is forbidden to view the resource.

The area where 401 could come into play with a visual login page is a front-end library that leverages the REST API using XHR requests, then relay the 401 response from the REST API back into a meaningful format on the login page.


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.
@sjagr> actually, I commented because I was linked your answer on my take on the same question, here: 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.
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: webmasters.stackexchange.com/questions/24443/…
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 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.
K
KernelDeimos

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.


I
ICW

If you try to log into a Google account with the wrong password, it will return a 200 response containing data that indicates the password was incorrect. For that reason, I just use a 200.

At the end of the day, which status code you use is purely a semantic issue and isn't going to change the functionality of your application. What really matters is that your application displays the correct information to the user.


Technically the correct answer, but just "Google does it that way" isn't really a good reason to do something
@Jake It's a good enough reason considering there's no advantage to doing it one way or another. This is one of those things where you just need to make sure you understand how the server is going to respond and react accordingly. Whether or not you do that by checking the status code has makes absolutely no difference to how the application functions nor does it make the application more/less maintainable. So, really, just do what you want with this one. The fact that Google does it this way just gives reassurance that it's a viable solution. Sometimes it's okay to say "it doesn't matter"