Internet Identity ideas

After Swapper and F2FI Protocol, I began to wonder, how to really make a maximum security web wallet, which also had the best possible UX and used all F2FI features. So in this thread, I am giving you the solution I came up with.

Run the Figma prototype here:

Internet Identity team can take parts or the whole thing. I believe no changes on the II backend are needed and it’s all frontend work.

It uses different mechanisms for mobile and desktop. The reason is, mobile is more secure and we can use localStorage to keep safe, while we can’t do that in desktop browsers that have extensions with read/ write permissions in them. A lot do, LastPass, Grammarly, Metamask, Ad blockers, Youtube downloaders, etc.

One realization I had @ desktop mode: Internet Identity in Iframe is better than opening a new window. You can keep it on and make multiple dialogs (like transaction signing) without saving anything in localStorage during the page session. After attempting to theoretically hack this setup with various attacks → I couldn’t figure a way that will result in an exploit even with a full read/write malicious extension.

Another realization Swapping is so much better than sending stuff and hoping you get something in return. It’s optional and harder to do, but really improves the UX and can be multi standard

Internet Identity only needs to take care of selecting identity, selecting a wallet, signing, and swapping. It doesn’t need to display wallet contents. Sites can do that as it works now.

So if there isn’t something I am missing, this should bring better UX with more security.


Wallet private keys always stay inside II and are only signing function calls (transaction signing) (Every site signs with the same key pair)

Identity private keys work like II keys right now (Every site gets a different key pair)

Identity keys shouldn’t be used to store assets. They are given to the frontend so it doesn’t have to prompt the user to sign every little click, like thumbs up on a post.

The app decides what to request, identity, wallet, or both.

Desktop version:

Opens in iframe. It stays on permanently and is hidden when not used. Becomes visible and expands for authentication or transaction signing and other F2FI protocol features. No need to refresh it, it can be used during the whole session

Extensions with full write/read access are way too powerful in browsers and we need II to be able to protect private keys and resist them.

Wallet private keys are kept in memory in anonymous function local scope and never leave it.

Identity private keys work like now

Something is used to freeze JS prototypes and prevent private key leaking.

As soon as the page loads (inside ) there is a script that runs and nothing can stop or prevent it, even extensions. It monitors for injected scripts from extensions trying to do DOM changes and replace the UI with a fake one. It monitors for requests towards webauthn trying to authenticate the malicious script. For protection - perhaps If attack is detected then a message is sent to the parent window to destroy the iframe.

Loses the keys if someone hits refresh. If single-page applications are done right, no refreshing will be needed.

Mobile version:
Opens in a window like now or iframe

Wallet private keys are stored inside the II window in localStorage. Mobile browsers don’t have extensions with full read/write access so keys are safe this way.

Wont loose the keys if someone refreshes the page

Backup phrase can only be retrieved from the mobile version - a desktop extension can always read it.

Related posts:
Swapper - Swapper. Atomic swap | multi-token | multi-standard | multi-type NFT / FT
F2FI Protocol - Frontend-to-Frontend Identity Protocol (F2FI)

Identicons used: (SCHUMANNCOMBO — User Interface & Icon Design)


Thank you @infu - that is a great post with some really good observations!

There’s one problem with iframes, unfortunately: Browsers do not necessarily give the same access to iframes as they give to full pages. For instance, if some page is embedded in an iframe in page A on Safari, and the same page is embedded in page B, those two do not share state. (For Firefox and Brave do something similar that depends on the privacy settings.) IMO that is a great feature for privacy, but it unfortunately makes developing with iframes across browsers harder. I also seem to remember that there is a restriction in accessing web authentication credentials from iframes (again) at least in Safari, but we’d have to re-evaluate that to be sure.

We have also been discussing several similar features (like the one you called the “wallet private keys” here). So I hope we’ll be picking some of them up. But yeah, lots of great insights, thank you for the post!


You are welcome.

I guess the problem is, that when someone opens a new tab, it won’t be authenticated. Why would we need the iframes to share state otherwise

Just checked with my desktop & mobile Safari here WebAuthn checker - IFRAME and both worked. Maybe others reading this can also check with their browsers?

I should try to hack something quick to see what the real implementation problems are. My ideas are only theoretically working now

I think what we’d need to check is having the credential be created in an iframe embedded from origin A and try to access the same credential in an iframe embedded from origin B.


Ok, I see now what the problem is.

And this is only half of what’s needed. I guess it’s a security issue too they won’t be figuring it out soon.

Ok, there is a walkaround. The iframe can open a new window to II where auth happens. Checked that and it works. Then the iframe keeps working as originally planned and no more webauthn is required for the session.

Additionally, agentjs script could open the iframe with src:“blob:…” Most extensions will only inject scripts in https:*

Content script rules from various extensions:

Metamask: “matches”: [ “file:///”, “http:///”, “https:///” ],

Plug: “matches”: [ “http:///”, “https:///” ],


“matches”: [ “\u003Call_urls>” ],

Also it has exclude rules and the Plug team could exclude this way. Won’t solve a lot, but will make attackers job harder.
“exclude_matches”: [ “://”, “://*”, , … and more

“matches”: [ “http:///”, “https:///”, “file:///*” ],

Possible scenario:

  1. Agentjs creates iframe with src:blob
  2. Iframe opens new window to II where user authenticates only once
  3. Iframe has the private key now and gets minimized & expanded when needed

Ok, I will have to make the whole thing work to know to be sure

  1. XSS attacks are easy to avoid. Avoiding MITB attacks is an art form. Must read, the following article claims they have solved Man In The Browser attacks.
    (DOMtegrity: ensuring web page integrity against malicious browser extensions | SpringerLink)

A similar solution could be used. MutationObserver looking for DOM changes. Placed in every browsing context. (dapp browsing context isn’t that important). The solution should allow developers to use II without caring too much about security.

  1. The rest is something like this and looks trivial. Dapp includes an iframe; iframe opens a popup; popup authenticates and returns the private key to the iframe; dapp prompts iframe for signing transactions.

My playground :

Initial interactions:

UX intro flow 1 - getting origin unique private keys

UX intro flow 2 - getting a signed transaction with private keys

UX intro flow 3 - swapping with private keys

Secondary interactions:

Ux flow S2 - signing

Ux flow S3 - swapping

We also haven’t explored Two-Factor Signing / Two-Factor Swap.

@bjoern I figured out a solution that doesn’t involve the Internet Identity team changing anything.
It can be added and optional and achieve the functionality I was describing. I am going to make a demo.
The iframe src can be pointing to another frontend canister. Doesn’t have to be II. It can still be NNS governed.

Both sites now use one key pair (same Principal) and Internet Identity. The frontend canister in the middle can be NNS governed or made immutable.



Very cool!!!

So what is happening here? II is delegating the same key to both domains? Or do you have a middle canister in here that is standing in?

1 Like

Yes, there is a canister in the middle. It’s inside the iframe. Basically means we don’t have to change Internet Identity to get this, we can make another frontend and give it to NNS to govern or make it immutable to gain maximum security.

If we add MITB protection, this solution will also resist malicious extensions along resisting malicious applications

If we let users write down their custom canister when authenticating, that could be the iframe src and it will allow secure user-owned wallets. Also, it could be something requiring a hardware wallet signature. The site only has to add a js library like now which allows users to write down the canister address. From there the site won’t care who is signing the transactions.

This is not supposed to be replacing the current Internet Identity flow. It’s more like a solution for better tokenization. Distrikt & Nuance and this kind of apps work perfectly fine with II. When the user wants to work with assets, that’s when you may want this.

If I understood your diagram correctly, this is similar to a concept we have been discussing internally: That additional iframe could actually be from the NNS frontend dapp (, so the user would have access to their main ICP accounts. So it’s like a wallet in an iframe, and one would have to define some protocol (probably based on postMessage) that dapps can use to interact with that wallet iframe. That’s roughly what you described as well, right?

1 Like

Yes, exactly. I would personally want to have both types of private keys in my dapps. One is app specific and another non-specific (A wallet traveling through apps). I will incentivize users to leave certain assets in their app-specific keys. This is what I call FunnelFi, it deals with assets, private keys, and user traffic, soulbound things, frontend canister governance.