You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on Feb 24, 2021. It is now read-only.
Thanks for a great looking project. Reading your docs, it looks like you're oriented towards establishing a session with an API using a cookie, whether standalone or integrated, after obtaining a JWT via ooth to show authentication status.
However:
I think there is a security issue with the use of non expiring JWTs
...which if fixed will allow use of ooth for sessionless authentication.
In addition, the use of the JWT tokens to transfer user data makes them less than ideal for sessionless authentication.
Non expiring JWT vulnerability
Looking at the ooth module, a non-expiring JWT is issued in exchange for a valid login. This means you can never log out a user - if they have the JWT, they can always pass it to the API for use, and it will be valid. Unless the API tracks a JWT blacklist, it will be unable to block malicious users. Tracking a blacklist means database calls, and the point of JWTs is to prove authentication without database access.
ooth/src/index.js:319:
getToken(user) {
return sign({ user }, this.sharedSecret);
}
I think it would be preferable to use short lived JWTs. This ensures that creating a session with the API can only be done for a limited amount of time. The session cookie can be as long as the API wishes.
The JWT expiry can be set as an exp field as observed by Passport.
getToken(user) {
return sign({
user,
exp: ...some time in the future
}, this.sharedSecret);
}
Enabling sessionless JWT authentication with refresh tokens
There's a significant use case of authenticating every API request with a JWT, instead of a cookie based session. This is the typical authentication method used in mobile apps, eg React Native. For this use case, if JWTs are to have an expiry, a method must be provided to obtain new JWTs without logging in every time.
In short, using the refresh token causes a database check to ensure:
the refresh token has not been revoked
the user can still be authenticated/has the same authorisation
The UI experience for the user is the same, but with more security:
the JWT token is used as before, enabling authenticated access without database calls, but expires regularly
the refresh token is used now and then to obtain a new JWT, without requiring the user to log in repeatedly. Its use triggers an authentication check to the database.
It seems this would be handy for many and will increase security.
JWT size/single concern contents
A disadvantage to using the ooth JWT token for authenticating all requests is that the ooth use does not quite adhere to the JWT spec....they are mean to be compact.
Ooth places the user profile uniqueFields information into the JWT. Okayish if the JWT is just used once to send to an API to establish a cookie-based session. But sending a large JWT token for every request becomes a problem when the user profile is large - eg Facebook data.
For instance, when logging in with the local strategy, the JWT token provided on login contains:
The JWT is being used to transfer user data, rather than the single concern of authentication status. This mix of concerns is reflected in the response body, which has both a user field, containing the same information as encoded in the token field.
The minimal, single-concern JWT token implementation would be to only place the user _id (and perhaps as a future feature authorisation data such as roles or similar) into the JWT. The fact of having a valid JWT with that user id means that authentication has occurred. If the API needs more user data, it can always access the database.
{
_id: <user id>,
exp: <UNIX time in future>,
iat: <UNIX time of issue>
}
Naturally, it's still very handy/essential for each strategy to administer profile fields. They can still be provided in the user field of the response body, or accessed by an API from the database.
Happy to potter along with a PR(s) to address these issues, but would be great to get thoughts before starting.
The text was updated successfully, but these errors were encountered:
(Extensively!) edited initial comment to make it clearer. As far as I can see, standalone issues a single non-expiring JWT in exchange for correct login details.
heysailor
changed the title
Refresh tokens
Expiring JWTs & Refresh tokens
Apr 13, 2018
Thanks for a great looking project. Reading your docs, it looks like you're oriented towards establishing a session with an API using a cookie, whether standalone or integrated, after obtaining a JWT via ooth to show authentication status.
However:
ooth
for sessionless authentication.Non expiring JWT vulnerability
Looking at the
ooth
module, a non-expiring JWT is issued in exchange for a valid login. This means you can never log out a user - if they have the JWT, they can always pass it to the API for use, and it will be valid. Unless the API tracks a JWT blacklist, it will be unable to block malicious users. Tracking a blacklist means database calls, and the point of JWTs is to prove authentication without database access.ooth/src/index.js:319:
I think it would be preferable to use short lived JWTs. This ensures that creating a session with the API can only be done for a limited amount of time. The session cookie can be as long as the API wishes.
The JWT expiry can be set as an
exp
field as observed byPassport
.Enabling sessionless JWT authentication with refresh tokens
There's a significant use case of authenticating every API request with a JWT, instead of a cookie based session. This is the typical authentication method used in mobile apps, eg React Native. For this use case, if JWTs are to have an expiry, a method must be provided to obtain new JWTs without logging in every time.
A refresh token is typically used: https://www.jaygould.co.uk/dev/2017/07/18/jwt-token-refresh-redux-react-native.html
In short, using the refresh token causes a database check to ensure:
The UI experience for the user is the same, but with more security:
It seems this would be handy for many and will increase security.
JWT size/single concern contents
A disadvantage to using the
ooth
JWT token for authenticating all requests is that theooth
use does not quite adhere to the JWT spec....they are mean to be compact.Ooth
places the user profileuniqueFields
information into the JWT. Okayish if the JWT is just used once to send to an API to establish a cookie-based session. But sending a large JWT token for every request becomes a problem when the user profile is large - eg Facebook data.For instance, when logging in with the
local
strategy, the JWT token provided on login contains:The JWT is being used to transfer user data, rather than the single concern of authentication status. This mix of concerns is reflected in the response body, which has both a user field, containing the same information as encoded in the token field.
The minimal, single-concern JWT token implementation would be to only place the user
_id
(and perhaps as a future feature authorisation data such as roles or similar) into the JWT. The fact of having a valid JWT with that user id means that authentication has occurred. If the API needs more user data, it can always access the database.This is how Meteor approaches tokens - a
resumeToken
isn't even a JWT; it's simply a random string which optionally expires, see line 589. Holding theresumeToken
signifies only that the user was authenticated; the token itself contains no data.Minimal JWT:
Naturally, it's still very handy/essential for each strategy to administer profile fields. They can still be provided in the
user
field of the response body, or accessed by an API from the database.Happy to potter along with a PR(s) to address these issues, but would be great to get thoughts before starting.
The text was updated successfully, but these errors were encountered: