# Persistent database in localStorage
In the previous step, we added a password pre-derivation step on the authentication method to ensure the security of password protection of a user's Seald identity.
We are still facing the problem that when a user opens a new tab in the application, despite having an authenticated session, the user has to retype their password to recover their Seald identity.
In this step, we will add an identity cache in localStorage so that the user can open a new tab.
In the mechanism implemented in the previous steps, the Seald identity of a user is retrieved from SSKS and then decrypted using the user's password. Thus, this identity is only kept in memory on the client side.
It is however desirable that when a user refreshes the page, or opens a new tab, they have access to their Seald identity without retyping a password.
The solution we recommend is to cache the database in the browser in the localStorage, and as a precaution, we recommend to protect this database in localStorage by a key stored in the backend called
The Seald database uses
nedb (opens new window), which in the browser does not necessarily use the localStorage, but choses (through
localForage (opens new window)) the best storage method between IndexedDB, WebSQL or localStorage depending on your browser.
When the user reopens the application, the
databaseKey will be retrieved from the backend via an authenticated session, and this key will be used to decrypt the
All this is done without any user interaction.
# Storing the database
To store the database, we will modify the
createIdentity function to save the database created in localStorage in encrypted format.
To do this, we add a
databasePath argument to store the database, and a
databaseKey argument to encrypt it.
This example choses to use a different
databaseKey per session. For a simpler implementation, you can instead opt to use a single
databaseKey per user for all their sessions.
sessionID in the
databasePath in order for it to be unique
Indeed, if a user logs-out, then logs-in again, the server will have generated a
databaseKey. Consequently, we cannot use the same database: the database
needs to be unique for each session, so we make the
databasePath change with
When we call the
createIdentity function, the identity is both saved on SSKS by the password known by the user, and in localStorage protected with the
Similarly, when we call
retrieveIdentity, the identity retrieved from SSKS is stored in localStorage encrypted with the
We will see later how to manage this
It is possible to create a different sub-identity for password protection and for protecting the local database.
Here, for simplicity, the same identity will be in the local database and protected by password.
# Identity retrieval
To retrieve the identity from the localStorage, we will create a function
retrieveIdentityFromLocalStorage which instantiates the SDK and checks that the database is in the expected state:
When calling the
retrieveIdentityFromLocalStorage function, the database is retrieved from the localStorage, decrypted with the
databaseKey and loaded in the SDK. We will see later how to manage this
# Managing the
databaseKey is a secret that protects the database stored in the localStorage, including the user's identity. It must be recoverable by the user in an authenticated way.
We will generate it from the backend, store it in session, and modify the frontend API client accordingly.
For faster instantiation, you can use a
databaseRawKey instead of the
databaseKey. For more details, see the "Using a persistent local database" section of the Identity Guide.
# Modification of the API in the backend
To do this, we will modify the following routes in the
- account creation:
POST /account/to generate, store and return the
POST /account/loginto generate, store and return the
GET /account/logoutto delete the
GET /account/to return the
Before modifying the routes, you have to import the
crypto module to generate random
databaseKey with function :
In the account creation and login routes, the
databaseKey is generated and returned:
In the status route, we return the
In the logout route, we remove the
databaseKey from the session:
# Modification of the API client in the frontend
We will reflect these changes in the API client
To do this we need to:
- store this
sessionIDas a properties of the
- retrieve them after the API calls in the static methods
# Retrieving from localStorage at initialization
The last step is to call
retrieveIdentityFromLocalStorage at application load in the
init function of
We need to:
- attempt a
GET /account/call to check if the browser has an authenticated session, and retrieve the
- try to retrieve and decrypt the database stored in localStorage.
If there is an error on either of these two steps, we set the
null which will take the user to the login step.
The identity is now cached, so a logged-in user can close the chat window and reopen it without having to retype their password.
There is still one last step for a satisfactory result: generate the license token on the backend.