This sounds like a case of authentication versus authorization.
JWTs are cryptographically signed claims about the originator of a request. A JWT might contain claims like "This request is for user X" and "User X has an administrator roles". Obtaining and providing this proof through passwords, signatures, and TLS is the domain of authentication - proving you are who you say you are.
What those claims mean to your server - what specific users and roles are allowed to do - is the problem of authorization. The difference between the two can be described with two scenarios. Suppose Bob wants to enter the restricted storage section of his company's warehouse, but first he must deal with a guard named Jim.
Scenario A - Authentication
- Bob: "Hello Jim, I'd like to enter restricted storage."
- Jim: "Have you got your badge?"
- Bob: "Nope, forgot it."
- Jim: "Sorry pal, no entry without a badge."
Scenario B - Authorization
- Bob: "Hello Jim, I'd like to enter restricted storage. Here's my badge."
- Jim: "Hey Bob, you need level 2 clearance to enter here. Sorry."
JWT expiration times are an authentication device used to prevent others from stealing them. If all your JWTs have five minute expiration times, it's not nearly as big a deal if they're stolen because they'll quickly become useless. However, the "session expiration" rule you discuss sounds like an authorization problem. Some change in state means that user X is no longer allowed to do something they used to be able to do. For instance, user Bob might have been fired - it doesn't matter that his badge says he's Bob anymore, because simply being Bob no longer gives him any authority with the company.
These two cases have distinct HTTP response codes: 401 Unauthorized
and 403 Forbidden
. The unfortunately named 401 code is for authentication issues such as missing, expired, or revoked credentials. 403 is for authorization, where the server knows exactly who you are but you're just not allowed to do the thing you're attempting to do. In the case of a user's account being deleted, attempting to do something with a JWT at an endpoint would result in a 403 Forbidden response. However, if the JWT is expired, the correct result would be 401 Unauthorized.
A common JWT pattern is to have "long lived" and "short lived" tokens. Long lived tokens are stored on the client like short lived tokens, but they're limited in scope and only used with your authorization system to obtain short lived tokens. Long lived tokens, as the name implies, have very long expiration periods - you can use them to request new tokens for days or weeks on end. Short lived tokens are the tokens you're describing, used with very short expiration times to interact with your system. Long lived tokens are useful to implement Remember Me functionality, so you don't need to supply your password every five minutes to get a new short lived token.
The "session invalidation" problem you're describing sounds similar to attempting to invalidate a long-lived JWT, as short lived ones are rarely stored server-side while long-lived ones are tracked in case they need to be revoked. In such a system, attempting to acquire credentials with a revoked long-lived token would result in 401 Unauthorized, because the user might technically be able to acquire credentials but the token they're using isn't suitable for the task. Then when the user attempts to acquire a new long lived token using their username and password, the system could respond with 403 Forbidden if they're kicked out of the system.
Best Answer
The first solution has a benefit of avoiding data duplication. The request plainly means:
If possible, I would even shorten it to
GET /api/friends
.On the other hand, if you expect to be able to access friends of other users, the second solution appears the good one. The request means:
but can also be:
For instance, one situation where such change can be possible is where a person can find her own friends, but also friends of her friends.