G
G
Gagydzer2019-08-21 11:51:27
Google Chrome
Gagydzer, 2019-08-21 11:51:27

How to implement tab-safe read/write to localStorage?

I was doing my own implementation of updating tokens for JWT authentication, I ran into the problem of synchronizing the update between several open tabs.
The essence of the problem: if you use localStorage to synchronize (the isRefreshing flag, which indicates that the token is already being updated at the moment, therefore the rest of the requests must wait and fly to the server with the new token after a while), then you can catch the situation when, after the token has become obsolete the request can fly from two tabs at the same time.
In fact, the second tab does not have time to track the flag change in localStorage, which was made by the first tab, because of which the second tab starts another update of the tokens, which leads to incorrect work of the program.

if (!isRefreshing()) { // проверка на то, обновляется ли токен в данный момент

    // проверка в другой вкладке фактически будет выполнена в данный момент времени

    updateRefreshFlag(true);
    // чтобы код был безопасным, вторая вкладка должна делать проверку в этот момент исполнения кода в первой вкладке

    // некоторый код обновления токена

}

function isRefreshing() {
    return JSON.parse(document.localStorage.getItem('is_refreshing'))
}

function updateRefreshFlag(v) {
    document.localStorage.setItem('is_refreshing', v)
}

The problem can be reproduced as follows:
1.
create two pages with the following code and open them in chrome in different tabs of the same window
2.
use the "reload all tabs" extension and reload them several times. We will see flag value: true or flag value: false in the console, which reproduces the problem
First tab
<body>
    <button id="btn">
    toogle flag
    </button>

    <script>
    const btn = document.getElementById('btn')

    btn.addEventListener('click', () => {
        setFlag(!getFlag())
    });
    setFlag(true)

    function setFlag(value) {
        window.localStorage.setItem('flag', value)
    }


    function getFlag() {
        return JSON.parse(window.localStorage.getItem('flag'))
    }
    </script>
</body>

Second tab
<body>
    <script>
    performAction()

    function setFlag(value) {
        window.localStorage.setItem('flag', value)
    }


    function getFlag() {
        return JSON.parse(window.localStorage.getItem('flag'))
    }


    function performAction() {
        const flagValue = getFlag()
        console.log('flag value: ', flagValue)
        if (flagValue) {
            console.log('flag value === true, set false then')
            setFlag(false)
        }
    }
    </script>
</body>

There is a problem of secure writing and reading data in localStorage and I'm interested in ways to solve it.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
R
rPman, 2019-08-22
@rPman

Alas, the spec clearly says:

4.5 Threads
Because of the use of the storage mutex, multiple browsing contexts will be able to access the local storage areas simultaneously in such a manner that scripts cannot detect any concurrent script execution.

But, you can try and simulate the mutexes yourself.
A classic example, we are looking for an atomic operation that will simultaneously mark the fact of a lock in the store and give out its status. For example, the mutex implementation: Here you get the number of processes that want to access the object and at the same time increase the number of locks, you can safely check this value for a long time, and if it is greater than 0, then wait a bit and try again later (of course, immediately reducing the number of locks ), when exactly, a separate conversation, for example, you can wrap up work with your database through your methods, where and call your callbacks. lockState=++localStorage['lockState'];

P
Philipp, 2019-08-22
@zoonman

1. https://developer.mozilla.org/en-US/docs/Mozilla/A...
2. You can communicate between tabs using ServiceWorkers and window.postMessage.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question