This guide shows developers how to add passkey-based authentication for better security and user experience. It explains both manual server and client setup, and how Descope simplifies this with a visual interface and pre-built flows.
This tutorial is by Kumar Harsh, a software developer and technical author from India. See more of his work on his website!
Using passkeys improves application security and user convenience. This guide details passkey implementation, from setup to deployment. Following these steps creates a secure and user-friendly authentication experience, reducing unauthorized access and building user trust.
Passkey Authentication: The Basics
Unlike vulnerable passwords, passkeys use public-key cryptography to enhance both security and user experience. Think of a vault: your identity is secured, accessible only with a unique key pair. Passkeys work similarly; each user has a private key (safely stored on their device), and a public key shared with websites.
Login involves the website sending a challenge to the user's device. The private key creates a unique signature (a digital fingerprint), verifying identity without revealing the key itself. This keeps logins secure even if the website is compromised.
Here's a visual representation:
Implementing Passkeys: The Manual Approach (and why you shouldn't)
While passkeys are innovative, manual implementation is complex and discouraged due to setup difficulty and security risks. It's best to use a supported library.
Generally, manual implementation involves:
navigator.credentials.create()
and navigator.credentials.get()
, the client guides users through authenticator interactions (fingerprint scans, PINs, etc.) and sends data to the server.Libraries like SimpleWebAuthn simplify this. It handles key generation, making the process easier than a manual approach.
(A React client and Node.js Express server example project using SimpleWebAuthn is available.)
Server-Side Setup (using SimpleWebAuthn)
The server uses the @simple-webauthn/server
package with four key endpoints:
/generate-registration-options
: Configures and generates registration options for the client, preventing multiple registrations from the same device. It also generates a challenge./verify-registration
: Verifies successful on-device registration and saves user details (public key, credential ID, device information) in the database./generate-authentication-options
: Returns authentication options, retrieving the registered device ID./verify-authentication
: Verifies successful on-device authentication using a registered device.This example omits database integration; you'll need to add that for production use.
Client-Side Setup (using SimpleWebAuthn)
The client needs two buttons (for registration and authentication). onRegistrationStart
requests configuration from /generate-registration-options
, then uses startRegistration()
from @simple-webauthn/browser
. After successful registration, /verify-registration
verifies the result. Authentication follows a similar pattern using /generate-authentication-options
, startAuthentication()
, and /verify-authentication
.
This manual method is complex and requires additional setup and maintenance for user identification and data storage. HTTPS setup requires extra steps.
The Easier Way: Implementing Passkeys with Descope
Descope simplifies passkey implementation, eliminating complex manual setup. It provides a no-code interface for managing authentication flows.
Creating Descope Flows
Setting up a React Project
npm create vite
.npm install @descope/react-sdk
.AuthProvider
in main.jsx
with your project ID.App.js
to implement the authentication flow.This simplified example shows how to integrate Descope's sign-up or sign-in flow:
// Simplified App.js example import { useDescope, useSession } from '@descope/react-sdk'; import { Descope } from '@descope/react-sdk'; const App = () => { const { isAuthenticated, isSessionLoading } = useSession(); const { logout } = useDescope(); return ( <div> {!isAuthenticated && ( <Descope flowId="sign-up-or-in" onSuccess={(e) => console.log(e.detail.user)} onError={(e) => console.log('Error!')} /> )} {isAuthenticated && <button onClick={logout}>Logout</button>} </div> ); };
Trying Out the App
Run npm run dev
and access the app at http://localhost:5173
. Register a user, set up passkeys, and test login. You can also enable passkey autofill in the Descope dashboard.
(The complete code is available on GitHub.)
Descope's Drag-and-Drop Authentication
Descope streamlines passkey implementation with a drag-and-drop interface for managing authentication flows. This simplifies setup and modification, making it accessible to developers of all skill levels. It allows for easier, faster, and more accessible logins.
Sign up for a free Descope account to learn more.
The above is the detailed content of Developer Guide: How to Implement Passkeys. For more information, please follow other related articles on the PHP Chinese website!