🔐 Something people have wanted for a long time in Inertia.js is a way to force a page to reload when navigating through history. The primary motivation is to prevent someone from seeing pages in history after logging out of an app.
Right now, if you sign out of an Inertia app and then go back in your history, you'll see the previous pages as they were when you visited them. This is just how the browser's history state works.
Yes, you can close your tab or even close your browser to end that session — but most browsers still allow reopening recently closed tabs, giving you access to that previous history state.
Unfortunately, browsers don't provide any APIs for clearing records out of history state — it's just not possible.
Since Inertia.js saves each page visit in history state, which includes all the page props (your data), it's possible for someone to go snooping through your history if you're on a public or shared computer and didn't use an incognito window.
Even if we got creative and added a flag to prevent end-users from restoring pages from history, a hacker could easily still access the data via the `history.state` property.
Well,
@joetannenbaum and I have been trying to find a solution to this in Inertia.js v2.0. It's been a journey.
We've explored all kinds of approaches to solve this — like storing the history state in localStorage, sessionStorage, IndexedDB, an in-memory cache, etc. While these storage mechanisms allow for clearing data, they all have other issues — for example, storage limits.
Turns out you can store a lot in history state, and honestly, that's where we want to store this data. That's where the browser expects you to put it! But we just can't clear it out. So, how do we solve that?
Well, I think we've found a way! Using the web crypto APIs, we're able to automatically encrypt the Inertia page props into history state. Then, we save an encryption key in the browser's session storage and use that to decrypt the page props when navigating through history.
However, and this is the important part, you can choose to delete this key from your session storage! When you do this, it automatically invalidates all your previous history entries — they can't be decrypted.
When Inertia can't decrypt a history entry (because the key has been rotated), it automatically loads a fresh copy of the page from the server — meaning if you've logged out of your app you'll be automatically redirected to the login page.
We're still working out the exact APIs, but enabling prop encryption will be something you do server-side. For example, in a Laravel app, you'll be able to add the `inertia:encrypt` middleware to the routes you want encrypted. (And yes, you can mix encrypted and non-encrypted routes!)
To clear history state on logout (or whenever you want), you can use the `Inertia::clearHistory()` method, which will instruct Inertia client-side to rotate the encryption key.
It's remarkable how quick the encryption and decryption are — most of the time it takes 1-2ms. It's so fast that we almost considered just having this enabled by default all the time.
We're still testing this out, and there's definitely a chance we hit a roadblock that invalidates this whole idea, but as of right now I'm optimistic that this might just work! 🤞