Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/elius94/users-session-manager

A simple Node.js module to manage users sessions on a web application or any kind of JS apps It uses a Singleton pattern to ensure that only one instance of the module is running at a time. SessionManager is a singleton class that can be used to manage users sessions. For every user that logs in, a new session is created and stored in the database. Every session has a unique ID that is generated by the system. Every session has a setTimeout that expires after a certain time (setSessionTimeout). When a user logs out, the session is deleted from the class. Every action fires an event that can be used to listen to the session manager.
https://github.com/elius94/users-session-manager

api javascript login login-page login-system nodejs npm npm-module npm-package npmjs session-management sessions socket-io users webapp webapps websocket

Last synced: about 24 hours ago
JSON representation

A simple Node.js module to manage users sessions on a web application or any kind of JS apps It uses a Singleton pattern to ensure that only one instance of the module is running at a time. SessionManager is a singleton class that can be used to manage users sessions. For every user that logs in, a new session is created and stored in the database. Every session has a unique ID that is generated by the system. Every session has a setTimeout that expires after a certain time (setSessionTimeout). When a user logs out, the session is deleted from the class. Every action fires an event that can be used to listen to the session manager.

Awesome Lists containing this project

README

        

[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/Elius94/users-session-manager/Node.js%20Package)](https://github.com/Elius94/users-session-manager/actions/workflows/release-package.yml) [![Coverage Status](https://coveralls.io/repos/github/Elius94/users-session-manager/badge.svg?branch=main)](https://coveralls.io/github/Elius94/users-session-manager?branch=main) [![npm version](https://badge.fury.io/js/users-session-manager.svg)](https://npmjs.com/package/users-session-manager) [![npm](https://img.shields.io/npm/dt/users-session-manager)](https://npmjs.com/package/users-session-manager) ![npm bundle size](https://img.shields.io/bundlephobia/min/users-session-manager) ![GitHub](https://img.shields.io/github/license/elius94/users-session-manager)

# users-session-manager
A simple Node.js module to manage users sessions on a web application or any kind of JS apps
It uses a Singleton pattern to ensure that only one instance of the module is running at a time.
SessionManager is a singleton class that can be used to manage users sessions.
For every user that logs in, a new session is created and stored in the database.
Every session has a unique ID that is generated by the system.
Every session has a setTimeout that expires after a certain time (setSessionTimeout).
When a user logs out, the session is deleted from the class.
Every action fires an event that can be used to listen to the session manager.

[![Readme Card](https://github-readme-stats.vercel.app/api/pin/?username=elius94&repo=users-session-manager&theme=github_dark&show_icons=true)](https://github.com/Elius94/users-session-manager) [![https://nodei.co/npm/users-session-manager.png?downloads=true&downloadRank=true&stars=true](https://nodei.co/npm/users-session-manager.png?downloads=true&downloadRank=true&stars=true)](https://www.npmjs.com/package/users-session-manager)

## Installation

Install with:
```sh
npm i users-session-manager
```

Example of usage:
```js
// Import module with ES6 syntax
import { SessionManager } from 'users-session-manager'
// or
// const SessionManager = require('users-session-manager')

// Create a new instance of the SessionManager class
const SM = new SessionManager()

// Change session Expiration time:
SM.setSessionTimeOut(6)

// Call this to initialize a new user session
SM.loadNewSession("Luca")
SM.loadNewSession("Fabio")

// You can listen to events emitted from this library through eventEmitter object exported
SM.on("activeUserDeleted", (key) => {
console.log(`User ${key} has been deleted`)
})

setInterval(() => {
console.log(SM.getLoggedUsers())
}, 5000)
```

## Example of Frontend and Backend session exchange
```js

// Frontend
let session_key = ""

/**
* Function to call try_login API
*
* @param {*} user username text
* @param {*} pwd password text
* @return {*} false if wrong login or the user table ROW of the selected user JSON format
*/
async function TryLogin(user, pwd) {
//console.log(ENDPOINT)
let credentials = {
"username": user,
"password": md5(pwd)
}
const rawResponse = await fetch(ENDPOINT + API_ROUTE, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'api_name': 'try_login'
},
body: JSON.stringify(credentials)
})
const user_data = await rawResponse.json()
if (user_data.length > 0)
session_key = user_data[0].session_key // save session key to the global variable.

//console.log("user_data: ", user_data)
return user_data
}

// And on the next calls, you can use the session_key to call the API

/**
* Function to call get_table_data API
*
* @param {*} siteid number
* @return {*} JSON object
*/
async function GetTableData(page) {
let body = {
page
}
const rawResponse = await fetch(ENDPOINT + API_ROUTE, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'session_key': session_key,
'api_name': 'get_table_data'
},
body: JSON.stringify(body)
})
const sectors = await rawResponse.json()
if (sectors.logout) Logout()
//console.log("sectors: ", sectors)
return sectors
}

// Backend

// API.js route (cutted from the original file)
...
case 'try_login':
response = {
accepted: false,
message: '',
user_data: {}
}
if (typeof(req.body) === 'object') {
try {
const body = req.body
const db_response = await db.tryLogin(body.username, body.password, true) // true to get the session key
if (db_response !== false) {
response.accepted = true
response.message = 'Welcome! 😘'
response.user_data = db_response
response.user_data.session_key = loadNewSession(body.username) // generate a new session key
} else {
response.accepted = false
response.message = 'Wrong username or password... Are you a f**ing HACKER? 💩💩💩'
}
} catch (error) {
response.accepted = false
response.message = 'Error in API call!'
response.user_data = null
} finally {
res.send(JSON.stringify(response))
}
}
break
case 'get_table_data':
response = {
accepted: false,
message: '',
table_data: {}
}
if (typeof(req.body) === 'object') {
try {
const body = req.body
if (await db.validateApiRequest(req.headers.session_key, "get_data")) {
const dbResponse = await db.getTableData(body.table)
if (dbResponse !== false) {
response.accepted = true
response.message = 'OK'
response.table_data = dbResponse
} else {
response.accepted = false
response.message = 'Error in API call!'
response.table_data = null
}
} else {
response.accepted = false
response.message = 'Action not allowed!'
console.warn('Action not allowed! api_name:', api_name)
}
} catch (error) {
response.accepted = false
response.message = 'Error in API call!'
response.analytics = null
} finally {
res.send(JSON.stringify(response))
}
}
break
...

// In file db.js (cutted from the original file)
...
/**
* @async
* @description Validate the session key
* @param {string} sessionKey Session key
* @param {string} action Action to validate
* @throws Will throw if query to DB will fail
* @returns {Promise} Return true if session key is valid, false otherwise
*/
async function validateApiRequest(sessionKey, action = undefined) {
const username = getUsernameFromSessionKey(sessionKey)
if (username) {
let user_data = undefined
const query_user_id = {
text: 'SELECT users_management, dataset_management ' +
'FROM users WHERE username = $1;',
values: [username]
}
try {
const userIdRes = await pool.query(query_user_id)
// console.log('[getUserProfilePic]', userProfilePicPathRes.rows)
if (!userIdRes.rows.length) {
user_data = undefined
return false
} else {
/* This may be a string or null */
user_data = userIdRes.rows[0]
}
} catch (err) {
console.error(err)
throw err.message
}
switch (action) {
case "get_data":
{
// check data validity here
}
break
default:
return true
}
}
return false
}
...
```

## Integrate with Socket.io server to notify clients

```js
// Import module with ES6 syntax
import { SessionManager } from '../index.js';

const http = require('http')

// Create a new instance of the SessionManager class
const SM = new SessionManager();

/**
* Create and start an ioSocket server
* @param {*} app
* "Express" handle
* @param {*} port
* Port the server should listen on
* @returns {SocketIO.Server}
* The newly created server
*/
function startServer(app, port) {
// Create an http server
const server = http.createServer(app)
server.listen(port)
server.on('error', function(error) { onError(error, port) })
server.on('listening', function() { onListening(server) })

// Create the socketIO server
const ENDPOINT = `localhost:3000`;
const { Server } = require("socket.io");
const io = new Server(server, {
cors: {
origin: ENDPOINT,
methods: ["GET", "POST"]
}
});

io.on('connection', (sk) => {
console.log('Browser Connected!')
sk.on('session_key', async function(data) {
const key = data.session_key
console.log(`User ${data.user} joined key ${key}`)
sk.join(key)
})
})

return io
}

SM.initSocketReferences(startServer(app, port)) // Initialize the socket references

SM.on("notifyClientToLogout", (io, key) => { // When a user logs out, notify the client
console.debug(`Session is expired for key ${key}... Logging out now!`)
io.in(key).emit('logout') // Emit the logout event to the client
})
```

## Exported APIs

- ```eventEmitter```:
Node.js Event Emitter object, is extended by the class. It fires the following events:
- 'error': Called when some error happens (eg: Session is rejected)
- 'sessionDeleted': Called when a session is deleted or if expired
- 'sessionCreated': Called when a user session is created
- 'notifyClientToLogout': Called when a session timer is expired, bind this to a Socket.io server to force clients to logout

## Integrate with metrics tools like PM2

```js
const io = require('@pm2/io') // Initialize the pm2 io module

// The PM2 IO metrics to monitor the number of connected users
const realtimeUser = io.counter({
name: 'Realtime Users',
id: 'app/realtime/users',
})

SM.on("sessionCreated", (key) => { // When a user logs out, notify the client
realtimeUser.inc() // Increment the number of active users
})

SM.on("sessionDeleted", (key) => { // When a user logs out, notify the client
realtimeUser.dec() // Decrement the number of active users
})
```

## Classes



SessionManagerEventEmitter


SessionManager is a class that manages the sessions of the users.



## Constants



sessions : Object


The sessions of the users.




MIN_SESSION_TIMEOUT : number


The minimum session timeout.




settings : Object


The settings of the session manager.



## Functions



log(msg)void


Logs a message to the console if the debug flag is set to true in the config.



## SessionManager ⇐ EventEmitter
SessionManager is a class that manages the sessions of the users.

**Kind**: global class
**Extends**: EventEmitter

* [SessionManager](#SessionManager) ⇐ EventEmitter
* [.setSessionTimeOut(sessionTimeout)](#SessionManager+setSessionTimeOut) ⇒ boolean
* [.getSessionTimeout()](#SessionManager+getSessionTimeout) ⇒ number
* [.getLoggedUsers()](#SessionManager+getLoggedUsers) ⇒ array
* [.initSocketReference(ioRef)](#SessionManager+initSocketReference) ⇒ boolean
* [.getSocketReference()](#SessionManager+getSocketReference) ⇒ SocketIO.Server
* [.loadNewSession(username)](#SessionManager+loadNewSession) ⇒ string
* [.setSessionData(key, data)](#SessionManager+setSessionData) ⇒ boolean
* [.getSessionData(key)](#SessionManager+getSessionData) ⇒ object
* [.restartSessionTimer(key)](#SessionManager+restartSessionTimer) ⇒ boolean
* [.getSessionDetails(key)](#SessionManager+getSessionDetails) ⇒ object \| boolean
* [.deleteSession(key)](#SessionManager+deleteSession) ⇒ boolean
* [.deleteAllSessions()](#SessionManager+deleteAllSessions) ⇒ boolean
* [.sendLogoutMessage(key)](#SessionManager+sendLogoutMessage) ⇒ boolean
* [.createNewSessionTimer(key, username)](#SessionManager+createNewSessionTimer) ⇒ NodeJS.Timeout
* [.checkSessionStatus(key)](#SessionManager+checkSessionStatus) ⇒ boolean
* [.getUsernameFromSessionKey(key)](#SessionManager+getUsernameFromSessionKey) ⇒ string

### sessionManager.setSessionTimeOut(sessionTimeout) ⇒ boolean
This function is used to set the session timeout

**Kind**: instance method of [SessionManager](#SessionManager)
**Returns**: boolean - true or false: true if ok

| Param | Type | Description |
| --- | --- | --- |
| sessionTimeout | number | The session timeout in seconds |

**Example**
```js
setSessionTimeOut(3000) // Returns true or false
```

### sessionManager.getSessionTimeout() ⇒ number
This function is used to get the session timeout

**Kind**: instance method of [SessionManager](#SessionManager)
**Returns**: number - The session timeout in seconds
**Example**
```js
getSessionTimeOut() // Returns 3000
```

### sessionManager.getLoggedUsers() ⇒ array
This function is used to get the list of logged users

**Kind**: instance method of [SessionManager](#SessionManager)
**Returns**: array - The list of logged users
**Example**
```js
getLoggedUsers() // Returns ['Gino', 'Gino2']
```

### sessionManager.initSocketReference(ioRef) ⇒ boolean
Function to copy the Socket IO http server reference

**Kind**: instance method of [SessionManager](#SessionManager)
**Returns**: boolean - true or false, true if ok

| Param | Type |
| --- | --- |
| ioRef | \* |

### sessionManager.getSocketReference() ⇒ SocketIO.Server
Function to get the socket reference

**Kind**: instance method of [SessionManager](#SessionManager)
**Returns**: SocketIO.Server - The socket reference

### sessionManager.loadNewSession(username) ⇒ string
Function to add users sessions in this module. Use it at login

**Kind**: instance method of [SessionManager](#SessionManager)
**Returns**: string - user unique key

| Param | Type | Description |
| --- | --- | --- |
| username | string | The username provided on successful login |

**Example**
```js
addSession('Gino') // Returns 'session_key'
```

### sessionManager.setSessionData(key, data) ⇒ boolean
Function to set the property 'data' of a session. Use it for example to store something in the session, like the user actions history, etc.

**Kind**: instance method of [SessionManager](#SessionManager)
**Returns**: boolean - true or false, true if ok
**Throws**:

- Error If the session_key is not found

| Param | Type | Description |
| --- | --- | --- |
| key | string | The session_key provided on successful login |
| data | object | The data to be stored in the session |

**Example**
```js
setSessionData('session_key', {'actions': ["logged in", ...]}) // Returns true or false
```

### sessionManager.getSessionData(key) ⇒ object
Function to get the property 'data' of a session. Use it for example to get the user actions history, etc.

**Kind**: instance method of [SessionManager](#SessionManager)
**Returns**: object - The data stored in the session
**Throws**:

- Error If the session_key is not found

| Param | Type | Description |
| --- | --- | --- |
| key | string | The session_key provided on successful login |

**Example**
```js
getSessionData('session_key') // Returns {'actions': ["logged in", ...]}
```

### sessionManager.restartSessionTimer(key) ⇒ boolean
Function that restart the session timer. Use it after an API call to keep the session alive.

**Kind**: instance method of [SessionManager](#SessionManager)
**Returns**: boolean - true or false, true if ok
**Throws**:

- Error If the session key is not found

| Param | Type | Description |
| --- | --- | --- |
| key | string | The session_key |

**Example**
```js
restartSessionTimer('session_key') // Returns true or false
```

### sessionManager.getSessionDetails(key) ⇒ object \| boolean
Function to get details of a session. Use it to get the username, the creation date and the data.

**Kind**: instance method of [SessionManager](#SessionManager)
**Returns**: object \| boolean - The session details or false if not found
**Throws**:

- Error If the session key is not found

| Param | Type | Description |
| --- | --- | --- |
| key | string | The session_key |

**Example**
```js
getSessionDetails('session_key') // Returns {'username': 'Gino', 'createdAt': 1523456789, 'data': {'actions': ["logged in", ...]}}
```

### sessionManager.deleteSession(key) ⇒ boolean
Function to delete users sessions in this module. Use it at client logout

**Kind**: instance method of [SessionManager](#SessionManager)
**Returns**: boolean - true or false, true if ok
**Throws**:

- Error If the session_key is not found

| Param | Type | Description |
| --- | --- | --- |
| key | string | The session_key provided on successful login |

**Example**
```js
deleteSession('session_key') // Returns true or false
```

### sessionManager.deleteAllSessions() ⇒ boolean
Function to delete all sessions

**Kind**: instance method of [SessionManager](#SessionManager)
**Returns**: boolean - true or false, true if ok

### sessionManager.sendLogoutMessage(key) ⇒ boolean
Use this to notify the client to logout with WebSocket

**Kind**: instance method of [SessionManager](#SessionManager)
**Returns**: boolean - true or false, true if ok

| Param | Type | Description |
| --- | --- | --- |
| key | string | The session_key |

**Example**
```js
sendLogoutMessage('session_key') // Returns true or false
```

### sessionManager.createNewSessionTimer(key, username) ⇒ NodeJS.Timeout
Function to return a new setTimeout object and start it.

**Kind**: instance method of [SessionManager](#SessionManager)

| Param | Type | Description |
| --- | --- | --- |
| key | string | The session_key |
| username | string | The username, only for logging features |

**Example**
```js
createNewSessionTimer('session_key', 'username') // Returns a new setTimeout object
```

### sessionManager.checkSessionStatus(key) ⇒ boolean
Use this before every API.js function execution.n the stored collection

**Kind**: instance method of [SessionManager](#SessionManager)
**Returns**: boolean - true or false: true if session is active
**Throws**:

- Error if the session is not valid
- Error if the session is expired

| Param | Type | Description |
| --- | --- | --- |
| key | string | the user key generated at login |

**Example**
```js
checkSessionStatus('my_session_key') // true or false
```

### sessionManager.getUsernameFromSessionKey(key) ⇒ string
Function to get the username from a session key

**Kind**: instance method of [SessionManager](#SessionManager)
**Returns**: string - The username or false if not found

| Param | Type | Description |
| --- | --- | --- |
| key | string | The session key |

**Example**
```js
getUsernameFromSessionKey('123456789_123456789') // 'username'
```

## sessions : Object
The sessions of the users.

**Kind**: global constant

## MIN\_SESSION\_TIMEOUT : number
The minimum session timeout.

**Kind**: global constant

## settings : Object
The settings of the session manager.

**Kind**: global constant

## log(msg) ⇒ void
Logs a message to the console if the debug flag is set to true in the config.

**Kind**: global function

| Param | Type |
| --- | --- |
| msg | string |