Dapp share
Embedded Wallets infrastructure at a glance
As described in the Embedded Wallets infrastructure, to keep
Embedded Wallets non-custodial, the private key is split into multiple parts called shares.
These shares are a part of the offchain multisig, where multiple shares are stored in different
places and can be used to reconstruct the private key dynamically in the user's frontend
application.
Typically, there are 3 shares:
ShareAis managed by a login service via node operators: This share is further split amongst a network of nodes and retrieved via conventional authentication flows.ShareBis stored on the user's device: Implementation is device and system specific. For example, on mobile devices, the share could be stored in device storage secured via biometrics.ShareCis a recovery share: An extra share to be kept by the user, possibly kept on a separate device, downloaded or based on user input with enough entropy (such as, password, security questions, hardware device).
Similar to existing 2FA systems, a user needs to prove ownership of at least 2 out of 3 (2/3) shares to retrieve their private key.
Mobile platform user experience
The user experience on mobile platforms differs from web platforms. On mobile, the user is redirected to a browser to sign in with their social accounts and then back to the app after authentication. This shifts context between two applications, whereas on web platforms the context remains within the browser only.
For a seamless sign-in flow, Shares A and B must be reconstructed.
Share B is managed by the sign-in service and is provided on successful authentication.
On web platforms, Share A is stored in the browser context.
You can still store it in the browser context on mobile devices, but this carries risks; users
may accidentally delete browser data.
This is a bigger problem on mobile because users don't realize the browser is used to sign in
within the app, and clearing browser data can cause sign-in to fail.
To address this, Embedded Wallets issues a dapp share, a backup share that you can store
directly in your app and use to reconstruct the private key after a successful sign-in.
Dapp share in iOS
After a successful sign-in, the SDK returns user details to your app.
Sample response in iOS
{
"userInfo": {
"email": "w3a-heroes@web3auth.com",
"name": "Web3Auth Heroes",
"profileImage": "https://lh3.googleusercontent.com/a/Ajjjsdsmdjmnm...",
"authConnectionId": "torus",
"userId": "w3a-heroes@web3auth.com",
"authConnection": "google",
"groupedAuthConnectionId": "w3a-google-sapphire",
"dappShare": "", // 24 words of seed phrase will be sent only incase of custom auth connections
"idToken": "<jwtToken issued by Web3Auth>",
"oAuthIdToken": "<jwtToken issued by OAuth Provider>", // will be sent only incase of custom auth connections
"oAuthAccessToken": "<accessToken issued by OAuth Provider>", // will be sent only incase of custom auth connections
"isMfaEnabled": false // Returns whether the user has enabled MFA or not
}
}
The response includes a dappShare field, a 24-word seed phrase that can reconstruct the
private key.
dappShare supplements Share A and represents half of the private key.
You can store the dapp share safely in your app's local storage.
During sign-in, the user's social account provides one share, and your app provides the dapp
share, removing the need to store a share in the browser context.
Pass the stored dapp share value in the connectTo call.
dappShare is only available for custom auth connections, not standard Embedded Wallets auth
connections.
This ensures your app only has access to the share corresponding to your users' private keys.
To use dapp share, you must use the
custom authentication feature.
Dapp share is only returned to users who have enabled 2FA on their account.
try await web3Auth.connectTo(
loginParams: LoginParams(
authConnection: selectedAuthConnection,
dappShare: "<24 words seed phrase>"
)
)
Example
import Foundation
import Web3Auth
class ViewModel: ObservableObject {
var web3Auth: Web3Auth?
@Published var loggedIn: Bool = false
@Published var userInfo: Web3AuthUserInfo?
@Published var isLoading = false
@Published var navigationTitle: String = ""
func setup() async {
guard web3Auth == nil else { return }
await MainActor.run {
isLoading = true
navigationTitle = "Loading"
}
web3Auth = try? await Web3Auth(
options: Web3AuthOptions(
clientId: "YOUR_WEB3AUTH_CLIENT_ID",
web3AuthNetwork: .SAPPHIRE_MAINNET,
redirectUrl: "com.yourapp.bundleid://auth"
)
)
await MainActor.run {
if self.web3Auth?.web3AuthResponse != nil {
userInfo = web3Auth?.web3AuthResponse?.userInfo
loggedIn = true
}
isLoading = false
navigationTitle = loggedIn ? "UserInfo" : "SignIn"
}
}
func login(authConnection: AuthConnection) {
Task {
do {
let result = try await web3Auth?.connectTo(
loginParams: LoginParams(
// authConnection can be .GOOGLE, .FACEBOOK, .APPLE etc
authConnection: authConnection,
dappShare: "<24 words seed phrase>"
)
)
await MainActor.run {
userInfo = result?.userInfo
loggedIn = true
}
} catch {
print("Error: \(error)")
}
}
}
}