Skip to main content

Authenticate a User with Email

This flow can both be used to login a user with only an email address, or to recover the account of a user that has lost their passkey credential with their email address. The end result is a valid TurnkeyClient which can also be used to add another authenbticator if needed.

1. Initialize Turnkey

import { Turnkey, TurnkeySDKBrowserConfig } from "@turnkey/sdk-browser";
import turnkeyConfig from "./turnkey.json"

const turnkey = new Turnkey(turnkeyConfig);

2. Initialize the Iframe Client

Note that the iframe client must be initialized with the dom element where the iframe will be injected. If you are using the react-sdk you can import the authIframeClient from the useTurnkey() hook without this step and the iframe dom element will be managed for you. Note that the iframeClient must be initialized before calling emailAuth because you need the iframePublicKey as a parameter to the emailAuth call.

import { Turnkey, TurnkeySDKBrowserConfig } from "@turnkey/sdk-browser";

const turnkeyConfig: TurnkeySDKBrowserConfig = {...};
const turnkey = new Turnkey(turnkeyConfig);

const iframeContainerId = "turnkey-auth-iframe-container-id";

// ensure the HTML element exists somewhere in the rendered DOM
<div id={iframeContainerId} />

const authIframeClient = await turnkey.iframeClient(document.getElementById(iframeContainerId))

3. Call emailAuth from your backend

await turnkey.serverSign(
"emailAuth",
[{
email: <userEmail>,
targetPublicKey: authIframeClient.iframePublicKey,
organizationId: <userSubOrganizationId>
}]
)

If you need to lookup the user subOrganizationId by email, you can call the getSubOrgIds method with the filterType parameter set to "EMAIL"

const subOrgIds = await turnkey.serverSign(
"getSubOrgIds",
[{
filterType: "EMAIL",
filterValue: <userEmail>
}]
)

const userSubOrganizationId = subOrgIds.organizationIds[0];

4. Inject the emailed credentialBundle into the iframe to authenticate the user

const authenticationResponse = await authIframeClient.injectCredentialBundle(credentialBundle);
if (authenticationResponse) {
// user is authenticated and can perform actions from the `iframeClient`
await authIframeClient.login();
navigate("/authenticated-route");
} else {
// credential bundle does not match emailed credential
navigate("/not-authenticated-route");
}

5. Make read requests on behalf of the authenticated user from the currentUserSession

const currentUserSession = await turnkey.currentUserSession();
const walletsResponse = await currentUserSession.getWallets()
const walletName = walletsResponse.wallets[0].walletName

6. Call the iframeClient directly for write requests

import { DEFAULT_ETHEREUM_ACCOUNTS } from "@turnkey/sdk-browser";
const newWalletResponse = await authIframeClient.createWallet({
walletName: "New Wallet for User",
accounts: DEFAULT_ETHEREUM_ACCOUNTS
})