Comments (22)
@derek-adair I have created gist with logout view .
@ngocngoan access token will be expired in ACCESS_TOKEN_LIFETIME and you can not refresh it, because refresh token blacklisted.
from djangorestframework-simplejwt.
Currently, there is no way to logout. I had planned to add a revocation view for tokens but I just don't have the time to do it right now.
from djangorestframework-simplejwt.
In my case I instantiated a CustomAccessToken
class inheriting the BlacklistMixin
too and in my logout view I just blacklist the token. I know it is not very effective from a database perspective, but it was the quickest workaround in my case.
One solution might be to edit the access token and add some kind of flag in the jwt encoding highlighting whether the token has been deactivated by logging out. I am not sure if this is the most effective way.
from djangorestframework-simplejwt.
If refresh token were saved on database we can add a validation against it and perhaps invalidate compromised tokens.
from djangorestframework-simplejwt.
Actually, that's probably the best way to do it as long as you're flushing the blacklist fairly frequently. If a token is expired, it will be flushed from the blacklist. There's really no other way to log someone out with JWT's other than to have a blacklist or to change the signing keys (logging everyone out).
from djangorestframework-simplejwt.
jpadilla/django-rest-framework-jwt#385 mentions the possibility of having different signing keys per user which allows to logout only the intended user, would there be a simple way to implement this?
from djangorestframework-simplejwt.
Hmm...yeah, I suppose that is another way. I can't think of a really straight forward way to do it right now. A possible drawback to that approach is that it could be difficult to coordinate using the same signing key across multiple services.
from djangorestframework-simplejwt.
You could add a judge that a token before the logout is invalid.
If add tokens into db, why not to use sessions.
from djangorestframework-simplejwt.
Hi!
I wrote a logout function, and I added a successful token refresh to the blacklist. But then I realized that when I send requests with access token in HTTP Header, I still get the value of success (code 200) without the unauthorized error (code 401) as expected.
from djangorestframework-simplejwt.
Would someone mind posting a gist of this working? Seems like something beneficial to the docs.
from djangorestframework-simplejwt.
Is it possible to change expires_at in current access token on logout request?
from djangorestframework-simplejwt.
Yes, but there are still unexpired access tokens with valid signatures out in the wild at that point. So doing that wouldn't really log anyone out.
from djangorestframework-simplejwt.
The way things are supposed to work is that you have some other communication channel to JWT-using services, such as a publish-subscribe setup, that would broadcast revoked tokens. Those other services would need to add them to their blacklists.
This channel, IMHO, is outside the scope of this project, because we have no idea what it is (dbus, zeromq, smtp, who knows). The module user would be expected to add this support themselves, using the blacklist module (or equivalent) to track blacklisted tokens.
from djangorestframework-simplejwt.
@greyhare Yeah that seems correct. Although maybe we could add something like a signal that people could hook into if they want to build their own blacklisting channels.
from djangorestframework-simplejwt.
Right now, I guess the signal could be "blacklist object created"
from djangorestframework-simplejwt.
maybe it's better to use cache or redis for blacklist storage backend? Cache may be expired for instance in 24h. So this allows not to use cron tasks
from djangorestframework-simplejwt.
I haven't used Redis much myself. Can you tell it when to expire an object? If so, then you can just set object expiration time to token expiration time.
Also, can you search for an object via its SHA-256 hash? The blacklists I've seen elsewhere just store the SHA-256 hashes of expired tokens, not the tokens themselves.
from djangorestframework-simplejwt.
The problem with Redis is that it's an in-memory database and therefore when it restarts it would log everyone back in (unless you use a Redis cluster or something).
from djangorestframework-simplejwt.
Could you guys please explain to me why do you store blacklisted
tokens instead of whitelisted
?
In the beginning, I was thinking about the saved database call on token validation, but if we are validating against blacklisted tokens, it will be the same, even worse.
If you store only VALID tokens, then it is easy to revoke and you almost no need to clean anything, except of expired refresh
tokens in the database based on created_at
date for instance.
In our setup we did use REDIS to store valid tokens for users as DB call is quite expensive to do on every request (as we are validating tokens against misuse and we rotate refresh token every now and then). But a lot of people just do not have REDIS setup ready and depending on the users count, you can have OOM of REDIS unexpectedly if you are not running managed service on AWS for instance.
from djangorestframework-simplejwt.
@sshishov I like that idea of whitelist. There are definitely pros and cons to each, and I think the time consumption on whitelisting is much less than a full scan for the blacklist table. (even with a bunch of bots spamming, it wouldn't make a difference).
HOWEVER, I think the biggest problem with whitelisting is the data storage requirement. If we're only blacklisting a certain few tokens, data is limited. If we accept majority of users, then you've got a huge database table that needs a cron job clearing that table for expired.
Whitelisting with Redis is the same story. You don't want to fill up the data store too quickly if you're accepting the majority of incoming requests.
from djangorestframework-simplejwt.
Hello @Andrew-Chen-Wang .
If you are using database, then every access of protected API will do DB call which is not desired when we are using JWT tokens (as it is self contained).
Using REDIS, it is completely different story:
- If we store only valid
refresh
tokens, we should not fill up quickly - Along with storing the token we can set TTL on the key (for instance
tokens:<user_id>:<token_id>
) the same value + 5 seconds of the token lifetime. The only issue with this approach if users will just start doing a lot oflogin
requests where newrefresh
tokens will be generated every request. And we cannot easily restrict the number of tokens per user as lookup in redis with a lot of data is not VERY fast also likeSCAN tokens:<user_id>:*
and limit to 10, but it if we are okay with this small delay on every refresh/login, then it is way to go. - Another approach is to use REDIS lists on the key
tokens:<user_id>
with TTL of inserted token. and update TTL on every new push to the list using (LPUSH, RPOP) and here you can limit number of tokens per user, say5
. If the returned value ofLPUSH
more than5
, then we will doRPOP
to remove the latest element from the list and update TTL of main key
It is just my assumptions and possible ways to solve the problem without degradation of the performance.
Update:
Points to consider:
- Also using
blacklist
approach you will add to the database/redis every "old" refresh token after successful rotation, or not? - If I am user and my refresh token leaked, but then I did re-login and started using OLD token. The "bad" guy can still use old leaked token to access data. And to blacklist it, we have to know which token exactly to blacklist, how we are going to get it, only from logs?
from djangorestframework-simplejwt.
The reason you want a blacklist instead of a whitelist is because it's a much shorter list, and tokens can be removed from the blacklist when they expire. So authentication is just "is the JWT itself valid, and not in the blacklist?" Which is a hash operation plus a lookup on a small tree.
Which gets back to one of the main reasons to use JWT is that you don't need to maintain a database of valid tokens shared among the hosts trying to authenticate the token. If you're okay with keeping a database of active tokens to authenticate against, you may as well be using the non-JWT random session token model.
Some things regarding refresh tokens:
- Maybe instead of generating a refresh token on login, you require the client to wait some time before requesting it? I.e. you can request a longer-lived refresh token, but only with a regular JWT that's at least n seconds old. Then folks who just need a one-and-done transaction don't have to deal with refresh tokens at all.
- There should only be one refresh token for a session ever. Refresh tokens are basically session tokens, with all their problems. Maybe allow the client to optionally provide the old refresh token in the refresh request so you can expire it immediately?
- Yes, you need to blacklist old refresh tokens. Maybe they need their own blacklist with its own rules?
- Or maybe you only issue new refresh tokens within some time of the expiration of an old one, and set the new token to only become valid a few seconds before the old one expires?
- "If I am user and my refresh token leaked, but then I did re-login and started using OLD token." Old which token, regular or refresh?
from djangorestframework-simplejwt.
Related Issues (20)
- Incorrect type hints for several classes/methods HOT 4
- Import "rest_framework_simplejwt.authentication" could not be resolved Pylance (reportMissingImports) HOT 2
- Import Error on Django 5 HOT 1
- ConnectionResetError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None)) with djangorestframework-jwt HOT 1
- How setup AWS Cognito with djangorestframework-simplejwt HOT 2
- CVE-2024-22513 HOT 1
- Security Issue HOT 3
- `Token` subclass' `for_user` method is typed to return a `Token` HOT 1
- encrypt username instead of user_id HOT 1
- The translation of the message "No active account found with the given credentials" does not work in various locales HOT 1
- TokenRefreshView doesn't register token_blacklist_outstandingtoken HOT 2
- How can we return custom JWT from dj-rest-auth instead of the session key HOT 1
- django5.0 is currently not supported HOT 1
- Why Outstanding token exist and why it stores raw refresh token
- Reported vulnerability in 5.3.1 HOT 3
- request.user.is_superuser and request.user.is_staff are False HOT 3
- Allow adding more field to payload of encoded `token` HOT 2
- Add JSON_ENCODER to the doc
- Can django 5.0 be used? Just use basic verification methods HOT 7
- TokenRefreshView should prevent users from refreshing token if the user is inactive
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from djangorestframework-simplejwt.