
In this post we’ll get into how you can set up a new NextJS project and use Turnkey to generate passkeys in the browser, and set them up as a user’s authentication method for wallets.
From here you could build a dApp and use them as embedded wallets, provide ways for users to fund a wallet or perform swaps and other transactions, and more.
Let’s get into it.
Prerequisites
This tutorial assumes you have some familiarity with web development and NextJS in particular, as well as NodeJS/NPM installed.
Create a new NextJS Project
Create a new NextJS project with the following command:
When prompted, you can accept the default options by hitting enter. Then, from inside of the directory, run:
The — legacy-peer-deps flag ensures compatibility with different package versions for your project. Now you can open the directory up in your favorite code editor, and run npm run dev to start a local dev server.
Initial Configuration
Create a .env file to store all of your environment variables. We’ll start with our Turnkey credentials.
You can generate an API keypair on Turnkey by heading to your Profile -> User Details, and then clicking Create API Key. Make sure that these stay private, and aren’t committed to your GitHub repository.
We set the rpId as localhost here for testing purposes, but in production you would need to switch this to the domain your web app is hosted on.
Updating Layout.tsx
We can remove most of the boilerplate code from the layout.tsx file.
The layout is essentially code that will wrap every page we create for our web application — so in this page, we will set up a Turnkey Provider to wrap the application. This makes Turnkey’s functionality available for when we generate passkeys on the client later on.
We also set up some basic metadata, like the web page’s title and description.
Setting some CSS globals
To keep things simple, we’ll update the globals.css file to just use the Tailwind directives, and theme our page separately.
Now we can create our page for users to sign up to our application with a Passkey.
Creating a Sign-Up Page
In page.tsx remove the boilerplate code, and add the following:
Let’s break this down step by step.
Inside of our homepage, the first thing we do is set up some state variables for the form users will submit to sign up with a passkey. This includes a username and email, as well as a loading state for our form.
We also set up a router for page switching, and initialized Turnkey’s passkey helper. This will let us generate a Passkey for a user when they press a button below, and redirect them to a new page if they sign up successfully.
We then create a function called `createSubOrg`, which does exactly what it says — when the form is submitted and the button is pressed, it will prompt the user to generate a Passkey and send detials of the credential to the backend of our application (which we’ll set up shortly).
Inside of the return statement after this, we set up our HTML for the component which will actually display a form on the screen.
We take in a username and an email, and when the Create Wallet with Passkey button is pressed, the form will submit and the sign up process will take place.
In production, you would likely need to add error-handling and validation for this process, which is omitted for the sake for simplicity.
Setting up a Server-Side API Route
So we have a page where users can submit a sign-up form with a passkey — now we need something to actually happen when this button is pressed.
For this, we’ll set up a new API route which creates a sub-organization with a user’s credentials, and generates an Ethereum wallet for them.
Create a new path within your app directory such as api/auth/route.ts.
Inside of it, add the following code:
The first thing we do is set up a Turnkey client using our API keys. This is an API route which executes server-side, as we don’t want to expose our API keys publicly on the frontend.
Using our Turnkey client, we simply accept the request containing the passkey credentials, and call createSubOrganization to create a sub-organization for the user, using their passkey as the auth method.
The rootQuorumThreshold is 1, meaning they are the only user who can access the sub-organization, and we pass in the default Ethereum curve settings to generate a wallet.
We then return the sub-organization ID in the response, so we can easily display it to the user.
Creating a wallet page
The last thing to do is create a wallet page.
In our main page.tsx we set up a redirect once a sub-organization is created, to redirect to a wallet page. Now, we need to actually create a wallet page for this to happen.
Create a new path wallet/page.tsx in your app directory, and add the following code:
We use useSearchParams to get the sub-organization ID passed in the URL so we can display it on the page, and useRouter to create a button send users back to the home page.
What’s next?
Congratulations, you just set up a non-custodial, passkey-powered app using Turnkey!
From here you can test it out yourself locally, add integrations to let users fund their wallets, display their balance, and set up granular auth control so users can only access data from their own sub-organization ID.
Check out our docs to see what you can build, and join our Slack for more technical tips.

.png)
