Import private key to be used by SFA SDK

Is there a way to import a private key to the web3auth nodes (using a custom verifier) so that it can be retrieved later on by the SFA SDK?

The use case is to seamlessly migrate users between verifiers. The idea is to have a dedicated “migration” web app where the user would first log in through the old (default) verifier, the app retrieves the private key. Subsequently, the user would log in through the new (custom) verifier and the app would initialize the account with the private key from the old verifier, ensuring the user would get the same private/key accounts they had when they logged in the “old” way.

I suspect this function can do exactly that but seems pretty low level: https://github.com/torusresearch/torus.js/blob/eb36f01715f3d3a9e3e668de3a98448e6a188bd3/src/torus.ts#L153 If it is the right function, a snippet showcasing how to use it would be very helpful

I described some attempts to do this in this related topic: Detecting whether user already created a key for given default verifier/ClientID - #7 by rafael.korbas but they weren’t successful, because the SDK after login kept asking me for a second share of the key - perhaps I wasn’t setting correctly the metadata of the key on the network, but could be anything else

The key initialization described in Using Web3Auth Core Kit tKey SDK in a React Application | Web3Auth seems to cover only the “1/2” flow, but for SFA I believe we would somehow need to initialize the key for a “1/1” flow for which I didn’t find any example so far

@rafael.korbas Your request has been forwarded our team and we will get back with further updates.

1 Like

I dug deeper and it seems that the key can indeed be imported with the imporPrivateKey() call using solely web3auth SFA SDK, the catch is that the key will be correctly imported (i.e. same key returned) only on non-legacy networks/v2 users (not sure exactly why, but found branching related to legacy networks/v1 users so I guess it’s related to that):

import { TORUS_SAPPHIRE_NETWORK, Web3Auth } from "@web3auth/single-factor-auth";

const web3authSfa = new Web3Auth({
  clientId, // Get your Client ID from Web3Auth Dashboard
  web3AuthNetwork: TORUS_SAPPHIRE_NETWORK.SAPPHIRE_MAINNET,
});

const verifier = "w3a-google-demo";
const idToken = response.credential; // google OAuth token after logging into google
const { email } = parseToken(idToken);
const verifierDetails = {
  verifier,
  verifierId: email,
};
let finalVerifierParams = { verifier_id: email };
let finalIdToken = idToken!;
const newPrivateKey = "<IMPORTED PRIVATE KEY HEX>";

const { torusNodeEndpoints, torusNodePub, torusIndexes } = await web3authSfa.nodeDetailManagerInstance!.getNodeDetails(verifierDetails);

const res = await web3authSfa.authInstance?.importPrivateKey(
  torusNodeEndpoints,
  torusIndexes,
  torusNodePub,
  verifier,
  finalVerifierParams,
  finalIdToken,
  newPrivateKey
);

// yay! it's the same as newPrivateKey
console.log("stored private key", res?.finalKeyData.privKey);

I think that’s the solution to my question, though I would welcome any advice/feedback on the security/usability (supposing we implement the usecase described in the question) of this solution and perhaps whether there isn’t some more straightforward way.

@rafael.korbas this use case is interesting. May I ask what happens to the old verifier? do you invalidate the key there so it cannot be used anymore? in that case, can you show how?

I don’t further touch the key in the old verifier, it just stays there. My intent is to just ensure the user gets the same private key on the new verifier as they did on the old one. The key is reconstructible anyway only for the user that would need to authenticate against this old verifier which sounds good to me.

Do you see any specific reason to “invalidate” the key in the old verifier? Bear in mind that the “old” verifier in my case is the default verifier and wiping the key (even if theoretically possible) would impact also any other projects relying on the default verifier, and I’d say that’s not desired.

To add to this, there seems to be a call (legacyKeyLookup) allowing you to detect if the user (identifier id) has stored a key on a verifier: https://github.com/torusresearch/torus.js/blob/f6f9afc3a26cec4e26b059de342d887a10f1e220/src/helpers/nodeUtils.ts#L616

However, the kicker is that in order to initialize a keypair (randomly) on the network you don’t have to be authenticated with the torus network: https://github.com/torusresearch/torus.js/blob/f6f9afc3a26cec4e26b059de342d887a10f1e220/src/helpers/nodeUtils.ts#L46 :confused: so I don’t see a reliable and simple way to tell if a user was migrated to the new verifier or somebody just (maliciously) initialized their key there at some point :frowning:

Hi @rafael.korbas. Thanks for your answer.

In case of a shared verifier, like the default verifier, I agree, it’s not ok to touch the user key. I’m working in a different scenario, where we want to migrate an account from SFA, to MFA. So far, I’ve been able to import the key with MFA, but the verifierId in the SFA SDK continues to work. I’m looking for a way to invalidate it son only a multi-factor authentication can retrieve the key once migrated.

I noticed the tkey SDK demo had some option to “reset” the account, maybe that could work for you too: https://github.com/Web3Auth/web3auth-core-kit-examples/blob/3b9f08a72a34ef59f17f423563e656cca276fbe7/tkey-web/quick-starts/tkey-react-quick-start/src/App.tsx#L282

1 Like