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
The JWT Bearer is currently being used to authenticate non-Browser Nexus clients (Python/Matlab/C#). The main problem here is the high complexity added to the code and usage restrictions added to ensure safety. One of the restrictions for users is that the bearer token they get cannot be used in parallel or they risk the token being invalidated. The reason for this behavior is that the bearer token approach requires to issue long-lived database-stored refresh tokens which are redeemed by the user to get asymmetrically signed and short-lived access tokens. Refresh tokens impose extra load on the database but can be revoked easily and access tokens simply need to be signature-validated (no database access) but cannot be revoked (which is why they are short-lived). To detect stealing of high-value refresh tokens, these tokens are being invalidated as soon as they are being used twice to get an access token. Using the refresh token in two or more scripts in parallel it is a matter of time until the refresh tokens gets being invalidated due to the mechanism described above.
Another big disadvantage of the current implementation is that the access token is not restricted in any way. Everything the user can do the access token can do.
Therefore we should copy what GitHub does with its personal access tokens (PAT): The user gets fine grained control over what the created PAT has access to (e.g. read access to a certain measurement catalog) and stores this as claims.
A PAT should consists of a long random base64 encoded secret number which is being given to the user and a list of the above mentioned claims.
To reduce the database load and to avoid the use of databases in general, Nexus should store all PAT and their attached claims into a .json file called PAT.json in a user specific folder. When a client issues a request to the API, the PAT.json file of the user the token belongs to should be loaded lazily and kept in memory. Therefore the token's random number should probably also include the user ID. When new tokens are being created by the user or when tokens are being deleted, the memory structure (ConcurrentyDictionary) and the PAT.json file are being updated immediately.
When the client (Python/Matlab/C#) issues a request to the catalogs API (for example) the following should be done:
Find the token using the long random secret number provided in the Authentication header's Bearer field
Check if the token allows access to the requested resource
Check if the user actually has access to the requested resource
Allow or deny access
Maybe do the following to implement this:
Create an authentication middleware which checks for the presence and validity of the Bearer token
If the token is valid, create a Principal object with the claims of the PAT but make sure to limit the claims to what the user is allowed to do
This means the request is authenticated and continues to be handled by the API controllers. The CatalogsController, for instance, can then check if the user has access to a specific catalog
To be considered: How to handle the case that the user has claim CAN_ACCESS_CATALOG = /a/b/* and the token has claim CAN_ACCESS_CATALOG = /a/b/c? This is difficult to compare. Better would be if the CatalogsController, for example, checks if the token claims allow access AND the user claims allow access. So we have two identities? Would be a possible solution. Also make sure that everything continues to work with cookie authentication, where it is similar in that we have two identities.
The text was updated successfully, but these errors were encountered:
The JWT Bearer is currently being used to authenticate non-Browser Nexus clients (Python/Matlab/C#). The main problem here is the high complexity added to the code and usage restrictions added to ensure safety. One of the restrictions for users is that the bearer token they get cannot be used in parallel or they risk the token being invalidated. The reason for this behavior is that the bearer token approach requires to issue long-lived database-stored refresh tokens which are redeemed by the user to get asymmetrically signed and short-lived access tokens. Refresh tokens impose extra load on the database but can be revoked easily and access tokens simply need to be signature-validated (no database access) but cannot be revoked (which is why they are short-lived). To detect stealing of high-value refresh tokens, these tokens are being invalidated as soon as they are being used twice to get an access token. Using the refresh token in two or more scripts in parallel it is a matter of time until the refresh tokens gets being invalidated due to the mechanism described above.
Another big disadvantage of the current implementation is that the access token is not restricted in any way. Everything the user can do the access token can do.
Therefore we should copy what GitHub does with its personal access tokens (PAT): The user gets fine grained control over what the created PAT has access to (e.g. read access to a certain measurement catalog) and stores this as
claims
.A PAT should consists of a long random base64 encoded secret number which is being given to the user and a list of the above mentioned claims.
To reduce the database load and to avoid the use of databases in general, Nexus should store all PAT and their attached claims into a .json file called
PAT.json
in a user specific folder. When a client issues a request to the API, thePAT.json
file of the user the token belongs to should be loaded lazily and kept in memory. Therefore the token's random number should probably also include the user ID. When new tokens are being created by the user or when tokens are being deleted, the memory structure (ConcurrentyDictionary
) and thePAT.json
file are being updated immediately.When the client (Python/Matlab/C#) issues a request to the catalogs API (for example) the following should be done:
Bearer
fieldMaybe do the following to implement this:
CatalogsController
, for instance, can then check if the user has access to a specific catalogTo be considered: How to handle the case that the user has claim
CAN_ACCESS_CATALOG
=/a/b/*
and the token has claimCAN_ACCESS_CATALOG
=/a/b/c
? This is difficult to compare. Better would be if theCatalogsController
, for example, checks if the token claims allow access AND the user claims allow access. So we have two identities? Would be a possible solution. Also make sure that everything continues to work with cookie authentication, where it is similar in that we have two identities.The text was updated successfully, but these errors were encountered: