-
-
Notifications
You must be signed in to change notification settings - Fork 328
Proposal of implementation for localStorage integration #1083
-
So, i was trying to include some login and user management features in a reactpy app and stumble uppon the fact that we dont have any way to access localStorage or any other client side stored data yet.
Thinking about that, i started implementing a way to integrate localStorage from the browser with the backend.
After some experimentation i was able to achieve this with the following logic:
- The backend will keep a copy of the localStorage content
- When loaded, the client will send to the server all items in its localStorage
- The server will receive the itens from localStorage and keep it in an object
- When in server side any item from the localStorage copy is changed, a message is sent to the client to update the real localStorage
The current state of this implementation is in this branch in my fork.
In src/py/reactpy/reactpy/samples/use_local_storage.py is a sample on how to use this method to access and alter localStorage.
How i wasnt yet able to make the login page using this new feature, i wont open a pull request for now.
But would like to bring to discussion and see what you guys think about this idea.
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 3 comments 19 replies
-
A while back added the ability for messages being sent between the client/server to have a "type". This is, at present, basically unused, but I think it's a perfect use case for it. One can image local-storage-set and local-storage-get message types which could be sent back and forth between the client/server. While there exists some infrastructure client-side for subscribing to certain message types, no such system exists server-side. Adding this capability is on my radar and something I'll be working on in the coming weeks.
The particular use case mentioned here is related to a broader discussion about how users should handle authentication in a ReactPy app (#828). While, from my understanding, you should always protect yourself against XSS, regardless of how client-side tokens are stored, doing so in local storage can make it easier to exploit. As such, whatever auth solution ReactPy provides will likely rely on HTTP-ONLY cookies (see solution 4 in above issue).
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
For the purpose of auth specifically, I think it's worth considering circumventing the client side entirely.
Right now, any framework with auth support retains a copy of the active user's session on server-side. There isn't any reason for us to do a round-trip from server->client->server just to fetch that data.
It's healthier for us to develop an implementation on a per-framework basis for server-side auth access. For example, Django SessionMiddleware stores the current Django auth session within the websocket scope. We could develop, or have dependencies for, ASGI middleware that does the same.
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
Yeah, i wasn't considering the XSS risks until now, thanks @rmorshea .
I had passed through issue #828 but wasn't able to reproduce the idom-auth-example-sanic suggestion. Because it uses the old nomenclature of the project i wasnt able go around and fix it. If there is any updates in this matter i wold be happy to contribute.
Anyway, even if not used for authentication purposes, maybe my use_local_storage method could be useful in the future.
Beta Was this translation helpful? Give feedback.
All reactions
-
As a general rule, you should never trust anything coming from a client.
The only thing that can be trusted is the server. The client should only be used to store non-important (or high entropy) data.
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
Although having localStorage access would be great for us, I do not believe localStorage access is required for an implementation of ReactPy auth sessions.
See my other comment.
Beta Was this translation helpful? Give feedback.
All reactions
-
I was looking into issue #1075 and localStorage access is part of it.
@Archmonger did you see how i did it? (here) Could easily apply the same logic for sessionStorage but would be good to have some feedback first.
Then i was thinking about proceeding with the other items listed in #1075
Beta Was this translation helpful? Give feedback.
All reactions
-
Ok, I think I understand. In your implementation, you sync local storage with the server before the first render. At that point, we just assume that local storage is always controlled server-side.
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
Yes, i thought that was the most practical way.
We could even add a security layer in the future by natively encrypting the localStorage in the server side before sending it to the client. This would guarantee integrity and security of data stored there.
Do you think we could apply this logic to other features listed in #1075 ?
Beta Was this translation helpful? Give feedback.
All reactions
-
Unfortunately, sending it before first paint ultimately slows down the speed of first paint. This ends up being an exponentially larger problem as more clients connect to one server.
Beta Was this translation helpful? Give feedback.
All reactions
-
Leaving technical questions aside, here's what the two interfaces would look like:
# SYNC USAGE local_storage = use_local_storage() value, set_value = use_state(local_storage.get_item("value")) @use_effect def set_local_storage_value(): local_storage.set_item(value)
# ASYNC USAGE local_storage = use_local_storage() value, set_value = use_state(None) @use_effect async def get_local_storage_value(): set_value(await local_storage.get_item("value")) @use_effect async def set_local_storage_value(): await local_storage.set_item(value) if values is None: # value has not loaded yet ... else: # value has loaded ...
Regardless of what approach you take set_item ought to be in an effect since it's a "side effect". So the main difference is that in the async API you need an extra effect to retrieve the value.
Beta Was this translation helpful? Give feedback.
All reactions
-
Beta Was this translation helpful? Give feedback.