JRFJWT
jrfjwt is an async/await package for working with JWT. The functional
uses one of PostgreSQL or MongoDB DBMS. Work with tokens is
conducted in the context of User, Device.
installation
$ nmp -i jrfjwt
Token content
access and refresh tokens contain
head head: {alg, typ}
| Name | Type | Description |
|---|
| alg | string | Encryption algorithm |
| typ | string | Token type |
payload head: {userId, rolesId, devId, iss, exp}
| Name | Type | Description |
|---|
| userId | string | user id |
| rolesId | array of string | user role id |
| devId | string | user device id |
| iss | string | ID of the token-generating side |
| exp | number | Token lifetime |
methods
constructor()
Just creates an object const jrfjwt = new JRFJWT();
init(options)
Initialization let res = await jrfjwt.init(options)
| Name | Type | Default value | Description |
|---|
| type | string | jrfjwt.dbType.MongoDB | What DBMS to use for storing tokens. To use MongoDB type: jrfjwt.dbType.MongoDB or type: 'mongoDB'. To use PostgreSQL type: jrfjwt.dbType.PostgreSQL or type: 'postgreSQL' |
| server | string | 'localhost' | DBMS Address |
| port | number | MongoDB port: 27100. PostgreSQL port: 5432 | DBMS Port |
| db | string | 'jrfjwt' | Database name in DBMS |
| collection | string | 'jwt' | Collection name, for MongoDB only |
| user | string | '' | DBMS username. The user must be the owner of the database. |
| password | string | '' | DBMS User Password |
| Name | Type | Default value | Description |
|---|
| alg | string | 'HS512' | Encryption algorithm |
| typ | string | 'JWT' | Token type |
| iss | string | '' | ID of the token-generating side |
| accessExp | string | '10min' | Access Token lifetime. Available are ms, sec, min, hour, day |
| refreshExp | string | '10day' | Refresh Token lifetime. Available are ms, sec, min, hour, day |
| salt | string | 'J*$#d84' | Salt |
| iterations | number | 100 | Number of iterations |
| hashLength | number | 64 | Hash length |
const JRFJWT = require('jrfjwt');
const jrfjwt = new JRFJWT();
let res = await jrfjwt.init({
db: {
type: jrfjwt.dbType.PostgreSQL,
server: 'localhost',
port: 5432,
db: 'jrfjwt_test',
user: 'jrfjwttest',
password: '12345678'
},
token: {
alg: 'HS512',
typ: 'JWT',
iss: '',
accessExp: '10min',
refreshExp: '10day',
salt: 'J*$#d73',
iterations: 100,
hashLength: 64
}
});
- Response - If it was not possible to connect to the database, a
'not init jrfjwt' exception will be thrown.
| res.okay | res.description | res.output | Description |
|---|
| true | '' | empty array | Initialization went well |
addNewUser(user)
Add a new user to the database of tokens.
| Name | Type | optional | Description |
|---|
| userId | string | | User id |
| rolesId | array of strings | true | Array id user roles |
let res = await jrfjwt.addNewUser({
userId: 'morty',
rolesId: ['yong', 'foreveryong']
});
| res.okay | res.description | res.output | Description |
|---|
| true | '' | id | User has been added. If MongoDB then output [0] contains the internal id of the added document 5c739e5cff97723bbc43bd9b. If PostgreSQL then output [0] contains the userId of the added user morty |
| false | 'not add' | empty | User failed to add. |
addNewUsers(users)
Add new users to the database of tokens.
| Name | Type | optional | Description |
|---|
| userId | string | | User id |
| rolesId | array of strings | true | Array id user roles |
let res = await jrfjwt.addNewUsers([
{
userId: 'morty',
rolesId: ['yong', 'foreveryong']
},
{
userId: 'rick',
rolesId: ['space', 'superspace']
}
]);
| res.okay | res.description | res.output | Description |
|---|
| true | '' | array of res add user | res.okay always true. The array res.output contains the results of the addition for each user |
| Name | Type | Description |
|---|
| user | obj | add user |
| add | boolean | true - user added, false - failed to add user |
| description | string | userId - if a user is added, 'not add' - if unable to add a user |
getUsers(id)
Get users, if id is not passed, all users are returned.
| Name | Type | optional | Description |
|---|
| id | string | true | User id |
let res = await jrfjwt.getUsers();
| res.okay | res.description | res.output | Description |
|---|
| true | '' | array of users | output [0] contains user (s) |
| Name | Type | Description |
|---|
| devId | string | user device id |
| access | string | access token |
| refresh | string | refresh token |
[ { userId: 'morty',
rolesId: [ 'yong', 'foreveryong' ],
tokens:
[ { devId: 'blaster',
access: 'accessToken1',
refresh: 'refreshToken1' },
{ devId: 'laser',
access: 'accessTokenLaser',
refresh: 'refreshTokenLaser' },
{ devId: 'loser',
access: 'accessTokenLoser',
refresh: 'refreshTokenLoser' } ],
tokensOld:
[ { devId: 'blaster',
access: 'accessToken1Old',
refresh: 'refreshToken1Old' },
{ devId: 'laser',
access: 'accessTokenLaserOld',
refresh: 'refreshTokenLaserOld' },
{ devId: 'Cheat',
access: 'accessTokenCheaatOld',
refresh: 'refreshTokenCheatOld' } ] } ]
updateRoles(userId, rolesId)
Update user roles
| Name | Type | optional | Description |
|---|
| userId | string | | user id |
| rolesId | array of strings | true | array of user role id; if the array is not set, then all user roles will be deleted from the user |
let res = await jrfjwt.getUsers('morty', ['user', 'guest']);
| res.okay | res.description | res.output | Description |
|---|
| true | '' | empty | Roles updated |
| false | 'not update' | empty | Roles not updated |
delUsers(id)
Delete user, if id is not passed, all users are deleted.
| Name | Type | optional | Description |
|---|
| id | string | true | user id |
let res = await jrfjwt.delUsers();
| res.okay | res.description | res.output | Description |
|---|
| true | 'deleted: X' | array of users | Managed to delete user (s). Where X is the number of deleted users. res.output if MongoDB, then contains the number of remote users, if PosgreSQL, it contains objects of remote users |
| false | '' | empty | Could not delete |
createTokens(userId)
Create a new token for user
| Name | Type | Description |
|---|
| userId | string | user id |
let res = await jrfjwt.createTokens('morty');
| res.okay | res.description | res.output | Description |
|---|
| true | '' | token | output[0] contains the created token |
| false | 'not create' | empty | Failed to create a new token. |
| Name | Type | Description |
|---|
| devId | string | generated device id |
| access | string | access token |
| refresh | string | refresh token |
updateTokens(userId, devId)
Update (reissue) user token for device.
| Name | Type | Description |
|---|
| userId | string | user id |
| devId | string | device id |
let res = await jrfjwt.updateTokens('morty', 'DKO32LS');
| res.okay | res.description | res.output | Description |
|---|
| true | '' | token | output[0] contains the updated token |
| false | 'not update' | empty | Failed to update token |
| Name | Type | Description |
|---|
| devId | string | user id |
| access | string | access token |
| refresh | string | refresh token |
delTokens(userId, devId)
Delete user device token.
| Name | Type | Description |
|---|
| userId | string | user id |
| devId | string | device id |
let res = await jrfjwt.delTokens('morty', 'DKO32LS');
| res.okay | res.description | res.output | Description |
|---|
| true | '' | empty | Token removed |
| false | 'not del' | empty | Could not delete token |
delAllTokens(userId)
Delete all user tokens.
| Name | Type | Description |
|---|
| userId | string | user id |
let res = await jrfjwt.delAllTokens('morty');
| res.okay | res.description | res.output | Description |
|---|
| true | '' | empty | Tokens removed |
| false | 'not del' | empty | Could not remove tokens |
isValid(access, refresh, rolesRules, usersRules)
Check token for validity. Check user access rights.
| Name | Type | optional | Description |
|---|
| access | string | | access user token |
| refresh | string | | refresh user token |
| rolesRules | obj | true | Role Access Validation Rules |
| usersRules | obj | true | User Access Verification Rules |
| Name | Type | optional | Description |
|---|
| exclude | array of strings | | array of id roles that are denied access |
| include | array of strings | | array id roles allowed access |
| defaultAccess | boolean | | default access if the role is not found in any of the lists. true - access is allowed, false - access is denied |
| Name | Type | optional | Description |
|---|
| exclude | array of strings | | array id users who are denied access |
| include | array of strings | | Array id of users who are allowed access |
| defaultAccess | boolean | | default access if users are not found in any of the lists. true - access is allowed, false - access is denied |
const rolesRules = {
exclude: ['superuser'],
include: [],
defaultAccess: false
};
let res = await token.isValid({access, refresh, rolesRules});
Logic
- Tokens are decoded; if decode failed, then return
res.description = 'invalid' - The access token's signature is checked, if the signature is not
valid, then return
res.description = 'access signature invalid' - The refresh token's signature is checked, if the signature is not
valid, then the return is
res.description = 'refresh signature invalid' - Search user
userId in the database, if the user is not found, then
returnres.description = 'not found user' Search access andrefresh tokens from user by devId.
At one time, a user by devId can have only one valid token
(token: {devId, access, refresh}) and one obsolete/previous
token (tokenOld: {devId, access, refresh}).
If the access andrefresh tokens are not found in the
token and tokenOld, then return res.description =
'tokens not found', the tokens by userId, devId are removed
If the access and refresh tokens were found in tokenOld, then
tokenOld is deleted, and access and refresh take on the value
from token (token: {devId, access, refresh} tokenOld : {}).
- It checks the lifetime of the
refresh token, if the lifetime has
expired, then return res.description = 'refresh token not live',
tokens are deleted by userId, devId - The access time of the
access token is checked, if the lifetime
has expired, the user creates a new token: {devId, access, refresh},
removes tokenOld: {}, the current access and refresh tokens are
placed in tokenOld: {devId, access, refresh}. A new token is passed
in the response res.tokensNew. If an error occurred while updating
the token, then return res.description = 'server error, repeat pleas' - If
usersRules was passed, then it is checked whether access is
allowed to the user. If userId is found in include, then
res.access = true, if userId is found in exclude, then
res.access = false, if userId is not found in include and in
exclude, then res.access = defaultAccess. If res.access = false,
then return res.description = 'no rights' - If
rolesRules was passed, then it is checked whether access to the
user is allowed by roles. If one of the roles of the user rolesId is
found in include, then res.access = true, if one of the user roles
of the rolesId is found in exclude, then res.access = false, if
none of user roles rolesId not found in include and in exclude,
then res.access = defaultAccess. If res.access = false, then return
res.description = 'no rights' - Return response
resres = {
okay: true,
description: '',
isValid: true,
access: true,
tokensNew: {devId, access, refresh}
};
Response
| res.okay | res.description | res.isValid | res.access | res.tokensNew | Description |
|---|
| false | 'invalid' | false | false | undefined | Invalid token failed to decode |
| false | 'access signature invalid' | false | false | undefined | Not valid token access signature |
| false | 'refresh signature invalid' | false | false | undefined | Not valid refresh token signature |
| false | 'not found user' | false | false | undefined | User is not found, tokens are deleted by userId, devId |
| false | 'tokens not found' | false | false | undefined | The access and refresh tokens are not found in tokens and tokensOld by userId, devId, tokens are deleted by userId, devId |
| false | 'refresh token not live' | false | false | undefined | The refresh token has expired, the tokens are deleted by userId, devId |
| false | 'server error, repeat pleas' | false | false | undefined | The token access lifetime has expired. An error occurred on the server while trying to update the token. |
| true | 'no rights' | true | false | undefined | Token is valid, but there is no access by user or by role. |
| true | '' | true | true | undefined | Token valid, there is access |
| true | '' | true | true | {devId, access, refresh} | Token valid, there is access. Token updated. |