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?
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:
{"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).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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With