[1]: https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba...
Does it keep a copy somewhere and check against it on every request?
Yes. The last time I did this we checked the X-Token header on every request, if it didn't exist or there were multiple we replied 401. If only one was there we checked a DB table of active tokens, if it wasn't there or had expired we replied 401. If it was there but wasn't associated with a role that had access to the requested resource, we replied 403. If it was not expired and had access we continued with the request.
As soon as you get away from "check authentication on every request" your attack vectors increase. As a bad actor, I no longer need to bypass your authentication, I just need to bypass whatever system you have in place to decide whether or not to authenticate me. That's generally going to be easier.
Yep, a store like Redis that has automatic row expiration is what I have used in the past. Most clients will often be bursty in their requests so a simple few second cache on API after verifying the token can also be useful/performant.
I don't even store role information in them, since authorization checks are performed on the server anyway.
If the client needs to know what a user is allowed to do with a resource (so it knows not to display certain buttons, etc.) I have the client do an OPTIONS call (with the token) to see what methods are allowed.
Lately, I've been thinking about replacing the whole JWT scheme with simple bearer tokens stored in the database, mostly because it would make revocation simple and I can't think of anything I would lose by giving up JWTs (a little storage space in the database?), and I don't think switching the type of bearer token I'm working with will actually be very painful implementation-wise. You know what, I'm adding a task to my backlog...
If you want to be completely stateless, you need to send the authorization info on each request, probably as basic auth headers.
This is actually simpler than implementing the Bearer token, for both client and server, but requires that the client retain the non-expiring username and password, rather than retaining the expiring, session-specific Bearer token.
IMO, this makes this simpler solution a non-starter. It becomes way too easy to leak credentials.
You also lose any method to force a re-authentication. With a token, I could expire with no activity for an hour and allow it to be good for a max of 2 hours.
[1] Users have a bad habit of just leaving computers. With a token, the worst case is someone has a short lived access to to something. With a user/pass left on the client worst case now becomes use/pass taken.
But most clients store their user/pass in their browser anyways so I'm not sure it's a security win for preventing credential loss.
You don't lose re-auth. The master system issuing API keys can revoke keys, too.
But anyways maybe we're talking about different contexts because I don't understand the scenario you're describing.
JWT is also poorly specified (no protocol under any circumstances should use negotiation, it does not support revocation, and it has been hammered home by the best security folks I know that public key cryptography is what you do when you don't have any other choice) and dangerous to use. Avoid it. Do the simplest thing that can possibly work. That's a session token. If, in the far and unlikely future, you are so successful that a single database call is so harmful, then you have the money to hire someone who doesn't have to Ask HN this question.
Also, mixing credentials into URL does not feel like a good separation of concerns, e.g. URLs are often logged and analyzed in separate logging/monitoring/analytic tools, so there is a bigger risk to have credentials leaked over some side-channel.
The API client should this token in every request that requires authentication, often in the header as `Authorization : Bearer 123TheToken456`.
JWT: If DB performance becomes a problem (or you want to expose signed session metadata) consider using JWT to provide session validation with the request itself. The downsides of JWT are that its often used to hold secret values (dont do this), or is a few kilobytes big which makes all requests slow, or stupid mistakes in signing and session validation that make it very insecure like allowing any request to just specify false permissions.