HTTP 401 Unauthorized when not using HTTP basic auth? - rest

When building a REST API that doesn't use HTTP basic authentication (but something else like an api-key) and the client provides invalid credentials, what HTTP Status Code are you supposed to return? 401 Unauthorized or 403 Forbidden?
The IANA HTTP Status Code Registry lists RFC7235, Section 3.1 as responsible for "401 Unauthorized", where it states:
The server generating a 401 response MUST send a WWW-Authenticate header field
Does that mean that a REST API should only ever return a 401 when using HTTP basic authentication but not when for example using authentication via an api-key?
Django seems to agree:
HTTP 401 responses must always include a WWW-Authenticate header, that instructs the client how to authenticate. HTTP 403 responses do not include the WWW-Authenticate header.
The kind of response that will be used depends on the authentication scheme.
While Richardson seems to disagree:
401 (“Unauthorized”)
Importance: High.
The client tried to operate on a protected resource without providing the proper authentication credentials. It may have provided the wrong credentials, or none at all.
The credentials may be a username and password, an API key, or an authentication
token—whatever the service in question is expecting. It’s common for a client to make
a request for a URI and accept a 401 just so it knows what kind of credentials to send
and in what format. [...]

You are assuming that the www-authenticate value needs to be basic. You can return a different value like "API-key" as the type of auth that needs to happen. So feel free to return 401 and www-authenticate header with some other value. You can even return multiple headers with different values indicating the different types of authentication that your app supports.

Related

REST api error response: should be informative or not?

I'm implementing a REST api and i'm in doubt about the response content in case of error. For instance, I use a jwt token for authentication. In case the client provides a wrong token, the server answers with a 401 status code with the following body
{
"status":"failed",
"details":"JWT token not valid"
}
In case the client doesn't provide the token, the server answers with a 401 status code with the following body
{
"status":"failed",
"details":"missing JWT token"
}
And so on.
These HTTP answers are informative, and they are useful when debugging. The problem is that an attacker now knows that the API uses a token, instead of basic authentication or other kind of authentication system.
For this reason, now I'm considering to answer only with the status code, and an empty body. This HTTP answer is not informative. An attacker doesn't know what's going on, and the same happens to me when debugging.
My question is: what is the best practice? Informative content or not? Is it necessary to create security with obscurity or not?
Thank you
If you return 401, the client will see what auth schemes are supported anyway:
"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." -- https://greenbytes.de/tech/webdav/rfc7235.html#status.401

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

determining web http authentication methods

How do you determine if a REST webservice is using Basic, Kerberos, NTLM, or one of the many other authentication methods?
When you send an unauthenticated request the service has to respond with a "HTTP/1.1 401 Unauthorized" and the response contains a WWW-Authenticate header that specifies what authentication scheme is expected (Basic, Digest), the security realm and any other specific value (like Digets's nonce). So if the server responds with:
HTTP/1.0 401 Unauthorized
WWW-Authenticate: Digest realm="example.com",
qop="auth,auth-int",
nonce="...",
opaque="..."
it wants a Digest authentication. If the response looks like:
HTTP/1.0 401 Unauthorized
WWW-Authenticate: Basic realm="example.com"
then it wants a Basic authentication. Some (poorly) implemented servers/sites don't handle the Basic correctly and respond directly with 403 Forbidden instead of challenging first.
NTLM is similar in as the server reponds with a 401 and a WWW-Authenticate header with the value NTLM, but there is no official public spec for it, since is Microsoft proprietary. There are various reverse engineered descriptions.
Unfortunately REST does not come with a WSDL style description of service to discover the authentication scheme used a priori.
You send it a request, presumably get an HTTP 401 code, and look at the WWW-Authenticate header that (per RFC 2616) the response MUST include. If instead you get a 403 or some other weird status, or a missing WWW-Authenticate header, you curse at website authors that don't follow the core HTTP RFC, and start sniffing the traffic to try to reverse engineer what nonstandard mess they've done this time;-).
If it's a black box scenario, I usually connect with Fiddler, and inspect the actual traffic.