How to distinguish between invalid token and lack of permission in rest - rest

What is the standard way to respond so the client can distinguish if their token is invalid/revoked OR they just tried to access some resource they do not have authorization for ? Do both use 401? Should I use a custom body?

Having an invalid or revoked token is basically the same as not having a token. This is typically indicated with the HTTP 401 Unauthorized status code. It means, we cannot establish who you are. (unauthorized should really have been unauthenticated)
The HTTP 403 Forbidden response means, we know who you are (you are authenticated), but you do not have permission to access the requested resource.

Related

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 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 HTTP code for authentication token expiry - 401 or 403?

401 seems to be used to indicate an authentication failure whereas 403 for an authorization failure (which means authentication succeeded?)
In case of an oauth flow if I try to authenticate with an expired token what is the right error code that prompts the client to refresh the token and try again?
A 401. The 401 vs 403 confusion is not new. See some discussion in a w3.org email here: https://lists.w3.org/Archives/Public/ietf-http-wg/2008AprJun/0418.html, though the cited RFC 2616 has been obsoleted.
Re 401, see https://www.rfc-editor.org/rfc/rfc7235#section-3.1
Re 403, see https://www.rfc-editor.org/rfc/rfc7231#section-6.5.3
From the 401 description, though "valid" is up for interpretation:
The 401 (Unauthorized) status code indicates that the request has not
been applied because it lacks valid authentication credentials for
the target resource.
But even more relevant, see RFC 6750 regarding Bearer Token authentication, Section 3, last paragraph.
https://www.rfc-editor.org/rfc/rfc6750#section-3
And in response to a protected resource request with an
authentication attempt using an expired access token:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="example",
error="invalid_token",
error_description="The access token expired"
Think about the boarding process in an airport. They check 2 things:
They check your identity card. This is authentication. Online, any token or user/password couple stands for your identity card.
They check you are in the passenger list for that plane (the plane is the resource you are trying to access). This is authorization. Online, the page the user is trying to access stands for the resource.
So now when you think about an access problem (token expired, token parsing failed, invalid password, user is not allowed) and which HTTP code you should return, you just have to think "if this issue was transposed into an airport scenario and I was denied access to the plane, would this have anything to do with the identity card check step?" If yes, this is 401. If not, this is 403.
For instance:
Missing token <=> Missing identity card <=> Rejected because of identity card check <=> 401
Expired token <=> Expired identity card <=> Rejected because of identity card check <=> 401
Malformed token <=> Unreadable/damaged identity card <=> Rejected because of identity card check => 401
User doesn't have privilege for the resource <=> Passenger is not allowed to access this plane <=> Not rejected because of identity card check => 403
You banned a user <=> Passenger is blacklisted <=> Not rejected because of identity card check => 403
etc.
TL;DR: 401
Long version, in addition to crunk1 (valid) answer:
401 would mean that the token was missing or invalid. In other words, it failed validation or parsing for some reason.
403 would mean that the token was successfully validated/parsed, but then the authorization to perform the action was denied for some reason.
Now, an expired token means that the token was successfully parsed but that the expiration date set in that token is already passed. Which is somewhat in-between if you consider that checking the expiration date is part of the authorization process. Personally I believe that it is part of the token validation, not the authorization, for those reasons:
There are some cases where the resource server (the API that receives and validates the token) would not even be able to know that the token is expired, and would return a 401 instead:
if the resource server uses its Authorization Server introspection endpoint and that one only returns {"active": false} with no further info, which means that the token is not valid (it might have been valid in the past, but that information was "forgotten" by the AS).
if the resource server tries to validate the token signature but the token is so old and expired that the validation keys have been renewed since it was issued. In that case even if the token is syntaxically valid but expired, the RS has no reason to trust that and should consider it as invalid instead.
Also, a 403 response would instruct the client that it is an authorization issue, so retrying with an new token carrying the same access rights doesn't have much chance to succeed, while a 401 would pass the information that the token was not accepted, so maybe retrying with a new fresh token might work.
For those reasons, I chose to return a 401 in my implementations. But TBH this doesn't matter much, since the token expiration is supposed to be handled by the client, based on the expires_in information returned by the AS at the same time as the token, more than by a return code from the API when the token is expired.

HTTP 401 Unauthorized when not using HTTP basic auth?

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.

Using HTTP status codes in web applications

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.