Using HTTP status codes in web applications - zend-framework

I'm currently building a web application (utilizing Zend Framework) and have gotten some of the basic HTTP status codes down, such as:
404 on missing controller/action
500 on server exception
3xx returned by Apache
At the moment I have just implemented some basic ACL checking that the user is authorized to access a certain resource. It's implemented as a controller plugin, doing its thing on the routeShutdown event. It works like follows:
Get the role of the user. If the user is not logged in, assign the role of 'guest'
Check that the user's rule has access to the resource
2.1. If the does not have access to the resource and is a guest, save the resource he was trying to access, and forward him to a login prompt. Once he has supplied his credentials, he is redirected back to the original resource (via a HTTP redirect status code)
2.2. If the user is authenticated and the ACL denies him access to the resource, he is forwarded to the error controller, to an action I've called noPrivilegies.
If the user does have access, let the request continue as usual.
Now, my questions:
Can/should I use HTTP 401 for the 2.1 scenario? It's not like I want a WWW-Authenticate header field sent by the client. I just need him to login through my login-form. But I still think that the request wasn't a 200 OK, since he didn't get access to the requested resource.
Can/should I use HTTP 401 for the 2.2 scenario? Same reason here, WWW-Authenticate won't help. Perhaps it's better to use HTTP 403 Forbidden?
Do you recommend any other status codes for these two scenarios?
What other status codes do you usually return from your application, and when are they applicable?

Provided that the guest role may be allowed to perform some actions, then no 4xx response or other form of error is warranted at stage 2.1 of your process because not being logged in is not an error.
Neither 401 nor 403 is really ideal for an application-level "permission denied", but weighing 401's "The response MUST include a WWW-Authenticate header field" against 403's "Authorization will not help", I would say (and most cases I've encountered to date seem to agree) that 401 is the appropriate response if you are requesting HTTP level authentication before proceeding and 403 is appropriate in all other cases. So probably 403 in your case.

I think that 403 is the correct response. Per the HTTP spec, 401 is for cases where HTTP-level authentication is possible and required, 403 is for cases where the user does not have permission to access the resource. In the case of your app, the user has logged in, and it's unreasonable to expect that s/he will be able to use a different account.

Normally I don't ever use the status codes to report 'application' level authentication failures. That's generally reported via the app.
And it makes sense to do that; because they can access the 'page' from a 'http' sense; they just can't access your applications processing of that page, if that makes sense.
What I'm saying is generally you don't worry about the codes, or set them yourself at all, when returning data to the client. Leave it to the webserver and provide an 'abstracted' method of responding; i.e. the typical 'invalid username or password' page, etc.
Just my view, though.

i've recently implemented something that works in a similar way, we return a 401 response when a user has to login and a 403 if after login they've tried accessing something that they don't have permission to access.
you can also set the reason phrase in the http response to something to denote the reason for the failure.

Even not specifically stated in HTTP spec, the common practice is
401 - For authentication error
403 - For authorization error
Try not to use 401 if you don't want authenticate user. I recently encountered a problem with a HTTP client (not one of the popular browsers) that it logs an error when it sees 401 but not WWW-Authenticate header. Granted this is a bug on the client side but it shows how people perceives 401.

Related

What status code should I use if old password doesn't match while changing password?

In back end I have a logic that authenticated users reset their password. I take the old password and a new one as parameters. If the old password doesn't match, then they will get an error, but I couldn't find a suitable status code for this.
Authentication middleware sends 401 Unauthorized when it fails, so I can't use 401 because of conflict. And I guess, even if it wasn't used, 401 wouldn't be the best suitable status in this case
403 Forbidden
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).
Keep in mind that status-codes are metadata, like the headers: they are data in standardized forms to allow general purpose components to understand the semantics of the requests/responses, without requiring that those components understand the details of the message-body.

REST unauthorized error meaning

I am asking maybe an open question about REST authentication practice. We use OpenID to authenticate with REST API. However there are some API where we do POST with body that also contain a secret (to support certain business rules). Now, if that secret is wrong am I still fine to return a 401 error? Does REST prescribe (like HTTP does) where token, password, secret should go in a REST call (e.g. always in HTTP Authorization header...)?
thanks
The 401 Unauthorized error is an HTTP status code that means the page you were trying to access cannot be loaded until you first log in with a valid user ID and password. If you have just logged in and received the 401 Unauthorized error, it means that the credentials you entered were invalid for some reason.

What WWW-Authenticate header should a http server return in a 401 response when using form-based authentication?

I have a web application with a Javascript part running on the browser. That frontend uses several HTTP endpoints (more or less REST). The frontend must be able to distinguish between 401 and 403 responses and must not receive the 3xx redirects usually used for human users.
Authorization is done with a plain form login (no Javascript involved there), then a session cookie is used (for both "REST" and normal requests).
What would be a correct value for the WWW-Authenticate header value?
From RFC 7235: "A server generating a 401 (Unauthorized) response MUST send a WWW-Authenticate header field containing at least one challenge."
The Hypertext Transfer Protocol (HTTP) Authentication Scheme Registry does not list any scheme for form-based authentication.
See also:
HTTP 401 Unauthorized when not using HTTP basic auth?
Authorization in RESTful HTTP API, 401 WWW-Authenticate
What would be a correct value for the WWW-Authenticate header value?
There's no point in returning 401 and WWW-Authenticate when you are not using HTTP Authentication as described in the RFC 7235. In HTTP Authentication, the client is expected to send the credentials in the Authorization header of the request with an authentication scheme token.
If you want to send the credentials in the request payload using POST, the 403 status code you be more suitable to indicate that the server has refused the request.
Since there is no standard challenge for this type of authentication, you are (as you predicted yourself) inventing your own.
I don't think there is a standard mechanism for specifying vendor tokens here, so I think the best thing you can do is use a token that's unlikely to clash with anything else.
Amazon has done this with AWS, and there's many others. My recommendation would be to use something like productname-schemename, for example acme-webauth.
In theory you should respond
HTTP/1.x 401 Unauthorized
WWW-Authenticate: cookie; cookie-name=my-session-cookie-name
However, real world internet browsers (user agents) do not really support this and in my experience the least bad option is to use HTTP status 403 for all of "Access Denied", "Unauthorized" or "Not allowed". If you have a REST service that's accessed with non-browser user-agents only, you could just follow the spec and return the above headers.
Also note that as described in RFC 7231 section 6.5.4 (https://www.rfc-editor.org/rfc/rfc7231#section-6.5.4) the server can respond with 404 for both "Access Denied" and "Not Found" so following should be okay for all user agents (browsers and standalone clients):
403 Unauthorized or Not allowed
404 Access Denied or Not Found
Or, you can just use 400 for any case because that should cause browser do fallback to generic error handling case. The HTTP status code 401 is especially problematic because it historically meant (at least in practice) that Basic Realm authentication is in use and the submitted HTTP header Authorization was not accepted. Because you cannot submit the session cookie via that header with commonly available browsers, those browsers have trouble handling 401 correctly when you use cookies for authentication. (According to the spec, HTTP 401 MUST include header WWW-Authenticate which should be used to figure out correct handling by the user agent but this doesn't seem to happen in reality with browsers.)
There is no HTTP authentication scheme for form based authentication.
Browsers implement basic, digest, etc. by showing a pop up where you can enter credentials.

What status code should a REST API return for login requests performed with wrong credentials?

I have found a lot of answers and explanations for the meanings of HTTP status codes. My question is specifically about the POST request to a login endpoint, which asks for username and password for example and the scenario where incorrect ones are provided.
Some thoughts:
400 Bad Response
I think this code is not appropriate, because it says the request was syntactically incorrect and not understood by the server, which is not the case here. The login data is just semantically not correct.
401 Unauthorized
Here is the tricky part for me.
If 401 can only occur on requests requiring an authentication header then this is not correct. But if 401 can occur on all requests, which require authentication (either as header or in the body) then 401 is a candidate.
403 Forbidden
Usually, 403 is returned if the user already is authenticated and known to the system but requested a resource he/she is not allowed to access.
The user definitely is not authenticated before the login. I don't know if there is a semantic for 403 for unauthenticated users.
I'm happy to be told the answer or hear your thoughts.
If a user is attempting to authenticate, but provides invalid credentials, the response should have a status of 401, regardless of if you are using Basic Authorization or not. 401 indicates that authentication failed, but the user can alter their request and attempt again.
If a user is authenticated, but not authorized to access the requested resource, then the response should have a status of 403. 403 indicates that the user is forbidden from accessing the resource, and no matter how they alter the request, they will not be permitted access.
In the scenario that your endpoint requires the credentials to be in the body of the request, you should return a 400 if the request body does not meet your specifications.
My question is specifically about the POST request to a login endpoint, which asks for username and password for example and the scenario where incorrect ones are provided.
It depends on how the credentials are sent:
If you are using HTTP Authentication (sending credentials in the Authorization header), you can return 401 to indicate that the credentials are invalid.
If you send credentials in the request body (for example a JSON with username and password), 401 doesn't seem to be the most suitable status code (once it's not a real HTTP Authentication). In this situation, consider 403 instead with a descriptive response payload.
The 403 status code also can be used to indicate authorization problems, that is, to indicate that a user is not allowed to perform an action.
401 for invalid credentials when using HTTP Authentication
403 for user logged in but attempting to access area that is not allowed

Correct return status code for authentication issues?

We have a rest service that we use to authenticate our clients. There are some cases where we want to report to the client more information than just "authorization failed". For example if their account gets locked after too many attempts we will report to the client that their account was locked. There are other instances, because of business use cases, where we will report other problems to them. Any of these issues will deny the user from logging in even if there username/password is correct.
I think probably returning an 401 Authorized is probably incorrect for these situations but after reviewing the http status codes i'm not sure what kind of return code would be appropriate. Maybe a 403 Forbidden? Realize I'll have to return wording for the issue to the client.
Even though the client has the right login and password, he doesn't have the mandatory permissions to go further, so I'd choose 403 Forbidden.
The difference between 401 Unauthorized and 403 Forbidden is detailed here.