Frontend-to-Frontend Identity Protocol (F2FI)

This thread is about the current application level IC identity crisis.

I will start by explaining the situation we are in, review it, and then offer better solutions.


For all intents and purposes. identity = wallet = private key holder

User-owned identity

  • Hardware
  • Software
  • Canister

There are no perfect software identities. The most user-owned one is the hardware wallet. Software wallets - if they can be updated by a third party massively within one hour with any code, one which can fetch the private keys - like extension wallets, they aren’t really user-owned, just appear as such.

User-owned canister identity (something new) - you can think of them like self deployed Internet Identity backend and frontend which serves only one user - the owner.

The most secure user-owned identity can be achieved with the Glacier Protocol - which has a 74-page manual that requires you to burn your laptop after using it for private key generation. That’s not really web3 material.

Application-owned identity
Application-owned identities use similar to the normal web paradigm. User registers and can use their registration to log in. The identity doesn’t work anywhere else but this one app. The user has to register in each application. If one application and its identity get hacked, other apps won’t be affected.
The easiest way to do it right now: Each application deploys its own Internet Identity backend and frontend (actually the frontend can be a component, not a new site)

Third-party owned identity

When a third party holds the keys or can update the software and fetch them at any moment.
The problems with these are that user assets are now controlled by 3rd party, which can use that as a platform to grow and steal the functionality from the applications which use it. Already happening with DEX & NFTs.

You can clearly see above where all the value is and why identities and wallets are getting heavily funded and growing in numbers. On the IC community side, pretty much 50% of the development goes to 3rd party wallets and identities.

In FunnelFi It matters also who owns it and what the connections do.

Internet Identity gives each application a different temporary private key. The application takes the key and has to protect it from extensions having full read/write access, supply chain attacks, injection, XSS, etc. A lot of security work is required, but still, it’s possible to achieve. If one application gets hacked, the rest won’t get affected. It also works well with games, because you don’t really want to sign every transaction on every move you make (think Chess).

Internet Identity is also governed by NNS with ICP. NNS can decide to grow II into a wallet + swap + NFT marketplace → and become a full-featured Binance-like themepark, but that is highly unlikely. It will be killing its hosted apps this way, which already pay it for computations & security.

Then we have the 3rd party identities which only give to apps signed transactions with one key. That makes them convenient for developers because currently there is no system for linking identities. One of the reasons why hackathon projects predominantly use extension wallets.

Let’s rate and order these solutions
User-empowering and decentralized ones first → third-party centralized ones last

(1) User-owned identity ← (2) Application-owned identity ← (3) NNS owned identity (Internet Identity) ← (4) some DAO owned identity frontend ← (5) browser extension identity (Plug) + privately owned database (Stoic)

All community developers working on identity solutions are now working on (4) and (5) because that’s where the money is, but it will also create a weak centralized application layer controlled by few entities. Currently, the frontend layer is at the mercy of two guys, who probably together own 70% of the keys used on the IC. And if you think that’s shocking, well - probably 90% of ETH keys are owned by one guy - the owner of Metamask. So we are going in the right direction, just need to put more effort into it.

Dfinity works on (2 - II is an open source project anyone can deploy) and (3 - NNS deployed II) and the ones working on (4) and (5) don’t like it, because it’s the better solution. They feel like the foundation is taking over their business.

The thing is - this shouldn’t be a business at all. This should be a crypto-illegal business the same way as drugs are. In the same way as drugs - it’s giving a short-term benefit while destroying the future. It’s basically making money centralizing things and racketeering small dapps, while the whole value in IC comes from decentralizing.

What we should be doing is working on (1) and (2), but these require community awareness. That’s why I am posting these articles.

Conclusion so far: The ultimate solution for users, applications, and the network as a whole
Every user deploys their own identity canister (frontend+backend) and they are the only controller. Whenever an app requires identity, the user enters a URL. The dapp connects to it on a frontend level and asks it for a temporary private key or to sign transactions. It works like a hardware wallet, but it’s on the chain and uses Webauthn. Works on mobile + desktop and doesn’t require installation of software or purchase of additional hardware. Users manually select which upgrade they want to install and it’s not auto updating. NNS is used to approve software upgrades, so nobody can racketeer apps by taking their functionality like DEX, marketplace, ads, one step closer to the user.

Now, let’s check how to get there.
We will need a Frontend-to-Frontend identity protocol (F2FI).

It will use PostMessage Window.postMessage() - Web APIs | MDN
Has 97.03% global coverage (canIuse)
It allows one website to open another in a window or iframe and talk with it securely. That’s used in Agentjs and Internet Identity. It’s also used to connect dapps to extension wallets.

NFID for example doesn’t use its own client js library, it uses Dfinity’s Agentjs. So we pretty much have some kind of protocol going on. It’s currently a spec covering one of the use cases.
II Spec here: internet-identity/ at main · dfinity/internet-identity · GitHub
As far as I can tell it can currently provide temporary keys, but can’t sign transactions, messages, etc.

Let’s see what the F2FI should be about:

  • provide temporary keys like II
  • sign message after user approval
  • provide public key
  • sign transactions after user approval
  • sign batch transactions after user approval (Note - it’s not very user-friendly, checking digits to make sure it’s all good)
  • provide advanced swap visual interface (optional, but improves security by visualizing what’s really happening inside the batch transactions). It will look something like this. The user doesn’t sign a batch of transactions but signs the whole offer (This interface has been used in games for 30 years) Basically the same in every game allows trading between parties that don’t trust each other.

It’s can be token type&standard agnostic. The backend for this is - Swapper - Swapper. Atomic swap | multi-token | multi-standard | multi-type NFT / FT
It can also supports F2FI interactions with soulbound tokens - proving to one app using one identity that you have proof of humanity or awards in another app using another identity. So there isn’t much you can’t do with a visual interface like that.

My latest project started with that mockup UI above and I didn’t know where it will lead at the time. Now in this post, all pieces get connected for the first time. I could just do it in a way to cowboy code finish the project and make something work, but I prefer fixing the problem at its root in a way that will improve the whole network.

The F2FI protocol can be used by all identity solutions. It will remove the need to install individual js libraries for every wallet/identity one adds to their app.

At some point, wallets holding soulbound tokens will also want to connect to other wallets, because transferring things is not an option.

The F2FI protocol will allow one site to use one library and interact with all identity/wallet providers and gradually transition to better more secure and decentralized solutions.

(1) User-owned identity ← (2) Application-owned identity ← (3) NNS owned identity (Internet Identity) ← (4) some DAO owned identity frontend ← (5) browser extension identity (Plug) + privately owned database (Stoic)

Currently, it looks like only I am working on this with a holistic approach. It will be great if more join so we can get it done faster.


Good post kind ser

1 Like

We’ve had a bounty open for months to get started on this:

Bounty - Motoko Wallet. It is still open and we have some enhancements coming in a bounty soon that take advantage of t-ecdsa.

@infu dies a much better job explaining the reason for this here.

Discussion here Bounty #15 - Motoko Wallet - $5,000+

I guess I am proposing two things, F2FI protocol, and user-owned identity canister. To be exact ICDevs doesn’t have F2FI protocol bounty as far as I can tell.

There are a few subtle but very important differences in my user-owned identity design.

From your spec:

With call_raw your wallet users will be able to call remote canisters from their wallet without the wallet having to upgrade your wallet with the known types of new services.

Internet Identity and what I have in mind doesn’t work like that. It’s not working like a proxy for messages using call_raw.
It gives you a temporary private key which you sign transactions with and then send them directly to IC. I guess IC checks if they have expired. They all point to one public key. (Note: I am not using the official complex explanation - its here The Internet Computer Interface Specification | Internet Computer Home )

  • Ability to log in with Plug, II, and StoicWallet

The idea behind my version of user-owned identity is that you don’t sign with anything else. It’s the master key holder. You hit your biometric webathn and you get a key like II. However, I guess you can use II, Google login, Facebook, Plug, Stoic, text phrase, but only as a backup in case, you lose your main webathn authentication, hardware wallet or you just don’t have supporting devices. The good thing is, that you can easily replace them. In this case your assets won’t be in the extension wallet, they will be in your canister wallet and the extension wallet will just sign a message to authenticate you.

The wallet also only needs to cover what the F2FI protocol requires to provide a fully functional alternative. It doesn’t need to do a lot of the things in the ICDevs spec to get the same functionality. If there is something needed there, it should go to the F2FI protocol.


So you want the canister to issue a delegation to your web auth-n key? That does make sense. I guess this bounty inverts it a bit. You’re looking to push a personal II for everyone. Makes sense.

Are you looking to use t-ecdsa for these delegations?

One of the goals here was to have an always-on identity that composable services could use. I’m wondering if there is a hybrid there somewhere…but not sure how you’d do it and preserve privacy unless you spawned off a canister for each one.

I guess since my canister can always issue the delegation to an authorized key they are “in” the canister as much as if the canister held them at the principal of the canister. If you wanted automation it could delegate the identity to itself and make an outgoing HTTP call to the IC in a meta way. ← Something like this is coming in a bounty soon. I still need to get this identity stuff down.

I would say, it provides a level of security to the end user comparable only to hardware wallets. All updates are approved by NNS and then also the user who manually approves them. This way even if a malicious update goes thru, it won’t hit more than a few users before someone figures it out.

Haven’t looked into the implementation yet.

Yeah, I get the benefits of a wallet canister knowing everything it owns - a multi-standard token index. It could be polymorphic like Swapper. However, it’s not something that needs a lot of security, it’s just there to speed up things.

I guess it’s best if it has many identities. Some of them are given around in Internet Identity style - works great with games.
Others can only be used to sign transactions and never reach 3rd party apps. Identity private keys only go to the user-owned wallet frontend - or don’t even go there, since the canister can sign the transaction.
It could also require a hardware ledger device signature for final approval.
The user can move tokens between them.

Ok….I’m sure you said this in your post, but it took rattling around in my head all day….but I get it now.

One question I have that will square the circle for me. I know that a canister principal can’t delegate to a key based principal because it doesn’t have a key. Can a key based principal delegate to a canister based principal? And if so, I wonder if we can push that into the intercanister communication somehow?

@bjoern Instead if an as field we can send along a delegation saying “look, this key said this principal can call a service as me” This way a canister could act as a t-ecdsa principal when the account holder is off line(according to the rules programmed into the on chain wallet/identity).

You wouldn’t be able to gate it as well(because delegations are currently all or nothing) so dao wallets would be off the table(n-of-m signing or vote to execute), but you’d get exactly all the other features you’d want out of an always on identity.

How hard would something like this be to set up though? Anything harder than II may hinder adoption.

Just so that I understand this, I am borrowing from The Internet Identity Specification | Internet Computer Home to express what I think is the intent.

The FuFi Protocol allows principals to :

  • Maintain identities on the Internet Computer

  • Log in with these identities using one out of a set of security devices

  • Manage their set of security devices

So it does not look much different then the internet identity of today; except that these are the principal-owned canister identities (self deployed Internet Identity Backend and FrontEnd) which serves only one principal. [“Principals are generic identifiers for canisters, users and possibly other concepts in the future”]

I just drew up a quick UI to illustrate these points.

Is this even in the ball park?

1 Like

No, because that ingress message delegation is between public keys. Of course you can now use canister signatures or ECDSA signatures in the canister, delegate to such a public key, and have the canister send ingress messages through the upcoming HTTP calls. But that doesn’t really seem a great solution.

What we really want here is delegation of authorization – whereas the “delegations” we have (I am regretting we landed on the name delegation actually) are more like “delegation” of authentication.

We should probably focus on making the F2FI Protocol first

It will work the same way II does. Imagine AgentJs has a few more options, for example, one which requests the other side to sign transactions instead of giving it a private key.

@mparikh yes, that’s about it. Just that the user-owned identity can be one canister holding many user-owned identities. The canister has one version.

I will cite the II spec

When a client application frontend wants to authenticate as a user, it uses a session key (e.g., Ed25519 or ECDSA), and by way of the authentication flow (details below) obtains a delegation chain that allows the session key to sign for the user’s main identity.

The delegation chain consists of one delegation, called the client delegation. It delegates from the user identity (for the given client application frontend) to the session key. This delegation is created by the Internet Identity Service Canister, and signed using a canister signature. This delegation is unscoped (valid for all canisters) and has a maximum lifetime of 8 days, with a default of 30 minutes.

The Internet Identity Service Frontend also manages an identity frontend delegation, delegating from the security device’s public key to a session key managed by this frontend, so that it can interact with the backend without having to invoke the security device for each signature.

  • canister signature link leads to private URL, I guess it’s using t-ecdsa ?

Did I get this right.

  1. Frontend - JS function creates a pub-private key pair (session key) storing it in local scope only
  2. Frontend sends the public key to Internet Identity backend
  3. II returns (public_key, user_id, expire_time) signed with its canister t-ecdsa
  4. The JS function now can make calls by signing with its private key, but only if it includes the II signature in the message, so IC can verify it

If it works like that, then these are true:
a) Anyone should be able to deploy their own Internet Identity backend with the same security as NNS II
b) if we opt out of storing the key in browser memory; if we avoid supply-chain library attacks; if we lockdown js with something like Javascript SES. Even extension with full read/write permissions can’t get our private key
c) It’s not possible to have man-in-the-middle attacks between the frontend and the identity canister
d) one node operator can’t get the identity canister private key, it will require majority of subnet nodes to gather their pieces

Doesnt @kpeacock 's work on storing delegated keypairs in indexdb instead of local storage somewhat help?

It does, you can’t get the keys out of the browser. But I guess, you can still inject malicious scripts and sign whatever you want.

Delegated keypairs aren’t of the correct type to store as a KeyPair, so they can’t be stored with extractable: false. The new ECDSAKeyIdentity can be stored as a KeyPair, but both cases are susceptible to XSS