If you're looking to add Passkey Login to your existing Next.js app, you're in the right place! Passkey login is a secure and user-friendly authentication method that eliminates the need for traditional passwords. By implementing passkeys, you can provide your users with a seamless and secure login experience.
In this tutorial, we'll walk you through the step-by-step process of adding a passkey login into your Next.js app using the Hanko Passkey API. We'll assume that you already have a Next.js app with authentication set up, so we won't focus on that here. Instead, we'll dive straight into adding Passkeys to your existing auth system.
If you're already using NextAuth for authentication in your Next.js app, we've got you covered! Check out our guide on integrating passkey login using our NextAuth Passkey Provider.
So, let's get started on upgrading your app's login experience! To make it easier for you to follow along, we have created a sample app that you can use as a reference throughout the tutorial.
We'll be implementing passkey functionality in two phases.
Make sure you have the passkey SDK installed.
To enable passkey registration, we define two server actions: startServerPasskeyRegistration
and finishServerPasskeyRegistration
.
The startServerPasskeyRegistration
function retrieves the user session, extracts the user ID and email, and initializes the passkey registration process using the passkeyApi.registration.initialize
method from the SDK. It returns the registration options to the client.
The finishServerPasskeyRegistration
function finalizes the passkey registration by calling passkeyApi.registration.finalize
with the provided credentials.
Now, it's time to implement passkey registration on the frontend. For that, we define an registerPasskey
function that will be triggered when the user clicks a button to register a new passkey.
Let's break down the steps involved in the registerPasskey
function:
1. We call the startServerPasskeyRegistration
server action to initialize the passkey registration process. This function returns the registration options needed to create a new passkey credential.
2. We use the create
function from the @github/webauthn-json
library to create a new passkey credential based on the registration options received from the server. The create function prompts the user to authenticate using their device's passkey mechanism (e.g., Touch ID, Face ID, or Windows Hello).
3. Once the user successfully authenticates and creates the passkey credential, we call the finishServerPasskeyRegistration
server action, passing the newly created credential as an argument. This function finalizes the passkey registration process on the server-side.
Now, to make it work we're missing one crucial step: getting the Tenant ID
and API key secret
from Hanko Cloud. For that, navigate over to Hanko, create an account, and set up your organization. Navigate to 'Create new project', select 'Passkey Infrastructure', and provide your project name and URL.
Note: It's recommended to create separate projects for your development and production environments. This way, you can use your frontend localhost URL for the development project and your production URL for the live project, ensuring a smooth transition between environments without the need to modify the 'App URL' later.
Obtain your Tenant ID
and create an API key, then add the Tenant ID
and API key secret
to your backend's '.env' file.
Now that you have your secrets added to your backend's .env
file, you should be all set to register a passkey. Go ahead and give it a try!
We'll need to create two more server actions. The startServerPasskeyLogin
function initializes the passkey login process by calling passkeyApi.login.initialize()
and returns the login options to the client.
The finishServerPasskeyLogin
function finalizes the passkey login by calling passkeyApi.login.finalize()
with the provided options and returns the login response.
Now, similar to passkey registration, inside the LoginPasskey
component, we define a signInWithPasskey
function, that will be triggered when the user clicks the "Sign in with a passkey" button.
Let's break down the steps involved in the signInWithPasskey
function:
1. We call the startServerPasskeyLogin
server action to initialize the passkey login process. This function returns the assertion
options needed to retrieve the passkey credential.
2. We use the get function from the @github/webauthn-json
library to retrieve the passkey credential based on the assertion options received from the server. The get function prompts the user to authenticate using their device's passkey mechanism.
3. Once the user successfully authenticates, we call the finishServerPasskeyLogin
server action, passing the retrieved credential as an argument. This function finalizes the passkey login process on the server-side and returns the login response.
4. We check if the login response contains a valid token. If not, we return null to indicate a failed login attempt.
5. If the login response contains a valid token, we extract the token and use the getUserID
function from @/lib/auth
to retrieve the user ID associated with the token.
6. If the user ID is not found, we return null to indicate a failed login attempt.
7. If the user ID is successfully retrieved, we call the loginWithPasskey
function, passing the user ID as an argument. This function checks if user with the provided id exists, then creates the session for the user.
Thats it! You now have a fully functional passkey login in your Next.js app, significantly enhancing the user experience and making the authentication process more seamless for your users 🚀 Feel free to reach out to us on Discord, if you get into any issues.
Github Repo: https://github.com/teamhanko/passkeys-nextjs