plugin-session

The session plugin is used to enable session support in your application. It will use the specified store as the session storage mechanism and extend the default thorin action with additional functionality.

Installation and usage
npm i --save thorin-plugin-session@1.x
'use strict';
// app.js entry file
const thorin = require('thorin');

thorin.addPlugin(require('thorin-plugin-session'));   // <- add this line
thorin.run((err) => {});

#update config/app.js with your configuration
# run to setup the store
node app.js --setup=plugin.session
Default configuration
  • storestringthe default store to use for persisting session information, see bellow additional info.
  • cookiePrefixstringif specified, the cookie key will have this prefix (eg: sess-qejkwjkernjkwnrjk)
  • cookieNamestring, tpsthe cookie name, used in Set-Cookie header.
  • secureboolean, false set to true to enable secure https-only cookies.
  • encryptboolean, true setting this to true will encrypt the contents of the session. By default, the session JSON is stored in plaintext.
  • authorizationboolean, true should the plugin add itself as an authorization source? This will attach the plain session id to intentObj.authorization and set the intentObj.authorizationSource to SESSION , if found empty
  • secretstringthe secret key used to sign the cookie id. This should differ from one app to another
  • expirenumber, 86400the number of seconds until a session expires.
  • namespacestring, sessionthe name of the namespace that will be used by the store, to save sessions.

Store configuration

  • store = file saves all the sessions using the file system, under the configured opt.path directory (defaults thorin.root + /sessions). This should be used in development mode.
  • store = redis saves all the sessions inside the specified redis store. This can also be the name of the store instance (eg, redis-session). All sessions will be stored using the configured namespace with the help of GET, SETEX, DEL,
  • store = sql saves all the sessions to the SQL database, using the opt.namespace as the sessions table name.

The stores will never store the actual session id set in the Set-Cookie header, but rather use the sha2 hash mechanism to hash them. When we check if a session exists, we hash the id and check if the hash exists. This mechanism makes it hard for any malicious user to use the session storage to impersonate users by using their session ids, since these ids are never in plain text.

Using the plugin with encrypt=true takes the security concerns to the next level. Before we store the session content (the JSON) to the specified store (file, sql, redis), we encrypt its content with the plaintext session id. This way, only users that posses the session id have access to the session's content.
A small proof of concept can be viewed bellow

'use strict';
let sessionId = thorin.util.randomString(32);   // let this be the generated session id.
let sessionData = {
   "someSession": "data right",     // let this be the session content
   "here": true
}
let storedSessionHash = thorin.util.sha2(sessionId),
   storedSessionData = thorin.util.encrypt(JSON.stringify(sessionData), sessionId);
save(storedSessionHash, storedSessionData) // Store the hashed & encrypted session information.
Plugin functionality
pluginObj.store
Expose the underlying SessionStore wrapper, see below for more info.
pluginObj.generateId() : String
Generates a new cryptographically safe random session ID, using the cookiePrefix specified.
pluginObj.signId(sid) : String
Signs the given plain session id using the specified secret. If no secret is found, returns the sid.
pluginObj.verifySignature(sid) : Boolean
Verifies that the incoming session id was previously signed by the app and is a valid one. If no secret was defined, returns true.
pluginObj.saveSession(sessionObj, fn)
Saves the given session ID with the attached data.
Note: when we store session ids, we do not store the actual sess ID as a key, we hash it like a password, so that session stealing is less likely if someone gains access to the session store.
  • sessionObjinstance of SessionData the session object to persist.
  • fnfunctionthe callback function to call once saved.
pluginObj.destroySession(sid, fn)
Destroys the given session id, deleting it from the session store.
  • sidstringthe plaintext session id coming from the user.
  • fnfunctionthe callback function to call once deleted.
pluginObj.readSession(sid, done, shouldUseSessionData)
Tries to read the information of a session from the data store. If shouldUseSessionData is set to true, wrap the result data in a SessionData object.
  • sidstringthe plaintext session id coming from the user.
  • fnfunctionthe callback function to call once read.
  • shouldUseSessionDataboolean, trueif set to false, callback with the raw session json object.
Extended thorin.Intent
intentObj.session
Contains the request's SessionData instance. It will contain all session data we want to persist.
'use strict';
thorin.dispatcher
   .addAction('my.action')
   .use((intentObj, next) => {
      if(!intentObj.session.value) {
         log.info('New session was just created');
         intentObj.session.value = "Hello world";
      }
      next();
   });

thorin.dispatcher
   .addAction('account.logout')
   .use((intentObj, next) => {
      intentObj.session.destroy();
      next();
   });
intentObj.skipSave()
This will not update the session store with the session changes.
The SessionData class
session.id
The current session id in plaintext.
session.isNew() : boolean
Verifies if the session was previously stored or has just been created.
session.isDestroyed() : boolean
Verifies if the session is marked to be destroyed.
session.createdAt() : Date
Returns the date the session was first created.
session.clear()
Removes all the data that was placed in the session but still persists the session id.
session.getData() : object
Internal function that returns the JSON object representation of the session. This is the object that will be persisted by the session store
session.shouldSave() : boolean
Internal function that checks if the session suffered any change and if we should store it.
The SessionStore class

We currently offer a wrapper for file, redis, sql. If you want your own session store, make sure it implements the following functionality.

store.read(id, fn)
Reads a session from the database, calling back with an error or the result object
store.save(id, data, fn)
Persists the given data to the store, under the given id
store.destroy(id, fn)
Deletes the associated session information given the session id.
Do you have a question or is something missing?

You can always create a new issue on GitHub or contact one of the core founders by chat.