Authentication
HumanWallet's authentication system is built on WebAuthn (passkeys), providing secure, passwordless authentication. The core package includes several functions for managing user authentication lifecycle.
Functions Overview
register()- Create new passkey-based accountslogin()- Authenticate existing usersreconnect()- Restore previous sessionsdisconnect()- End sessions and clear datahasAccount()- Check if user has existing account
register()
Creates a new passkey-based account for a user.
Function Signature
function register(
username: string,
config: Config,
): Promise<{ sessionKeyAccount: SessionKeyAccount; kernelClient: KernelClient }>Parameters
username: Unique identifier for the user (used for passkey creation)config: Configuration object fromcreateConfig()
Usage Example
import { createConfig, register } from "@humanwallet/core"
import { sepolia } from "viem/chains"
const config = createConfig({
projectId: "your-project-id",
chain: sepolia,
})
try {
const { sessionKeyAccount, kernelClient } = await register("alice", config)
console.log("Account created:", sessionKeyAccount.address)
// User is now authenticated and ready to interact
} catch (error) {
if (error.message.includes("User rejected")) {
console.log("User cancelled passkey creation")
} else {
console.error("Registration failed:", error)
}
}What Happens During Registration
- Passkey Creation: Browser prompts user to create a passkey using biometrics/PIN
- Account Generation: A smart contract wallet is created using the passkey
- Session Key: A temporary session key is generated for seamless interactions
- Storage: Authentication data is securely stored locally
login()
Authenticates an existing user with their passkey.
Function Signature
function login(
config: Config,
): Promise<{ sessionKeyAccount: SessionKeyAccount; kernelClient: KernelClient }>Parameters
config: Configuration object fromcreateConfig()
Usage Example
try {
const { sessionKeyAccount, kernelClient } = await login(config)
console.log("Logged in as:", sessionKeyAccount.address)
// User is authenticated and ready to interact
} catch (error) {
if (error.message.includes("User rejected")) {
console.log("User cancelled authentication")
} else if (error.message.includes("not found")) {
console.log("Account not found - user needs to register first")
} else {
console.error("Login failed:", error)
}
}What Happens During Login
- Passkey Authentication: Browser prompts user to authenticate with their passkey
- Account Recovery: The smart contract wallet is recovered using the passkey
- Session Restoration: A new session key is generated for interactions
- Storage Update: Fresh authentication data is stored locally
reconnect()
Restores a previous session using stored authentication data, avoiding the need for passkey authentication.
Function Signature
function reconnect(config: Config): Promise<{ sessionKeyAccount: SessionKeyAccount; kernelClient: KernelClient } | null>Parameters
config: Configuration object fromcreateConfig()
Usage Example
// Try to restore previous session
const result = await reconnect(config)
if (result) {
const { sessionKeyAccount, kernelClient } = result
console.log("Session restored for:", sessionKeyAccount.address)
// User is automatically authenticated
} else {
console.log("No previous session found")
// User needs to login or register
}When to Use Reconnect
- App Startup: Check if user has an active session
- Page Refresh: Restore authentication state
- Background Tasks: Maintain authentication for scheduled operations
disconnect()
Clears stored authentication data and ends the current session.
Function Signature
function disconnect(): Promise<void>Usage Example
await disconnect()
console.log("User logged out")
// All stored authentication data is cleared
// User will need to login again to interactWhat Gets Cleared
- Session keys and authentication tokens
- Locally stored account data
- Any cached user information
hasAccount()
Checks if the user has an existing account stored locally.
Function Signature
function hasAccount(): Promise<boolean>Usage Example
const userHasAccount = await hasAccount()
if (userHasAccount) {
// Try to reconnect or show login UI
const result = await reconnect(config)
if (!result) {
// Show login form
}
} else {
// Show registration form
}Authentication Flow Examples
Complete Authentication Flow
import { createConfig, hasAccount, reconnect, login, register } from "@humanwallet/core"
const config = createConfig({
projectId: "your-project-id",
chain: sepolia,
})
async function authenticateUser(username?: string) {
// Check if user has existing account
const hasExistingAccount = await hasAccount()
if (hasExistingAccount) {
// Try to restore session
const session = await reconnect(config)
if (session) {
return session // User is authenticated
}
// Session expired, need to login
return await login(config)
} else {
// New user, need to register
if (username) {
return await register(username, config)
} else {
throw new Error("Username required for registration")
}
}
}React Hook Example
import { useState, useEffect } from "react"
import { hasAccount, reconnect, login, register, disconnect } from "@humanwallet/core"
export function useAuth(config) {
const [account, setAccount] = useState(null)
const [isLoading, setIsLoading] = useState(true)
// Check for existing session on mount
useEffect(() => {
async function checkAuth() {
try {
const session = await reconnect(config)
if (session) {
setAccount(session.sessionKeyAccount)
}
} catch (error) {
console.error("Reconnect failed:", error)
} finally {
setIsLoading(false)
}
}
checkAuth()
}, [config])
const loginUser = async () => {
setIsLoading(true)
try {
const { sessionKeyAccount } = await login(config)
setAccount(sessionKeyAccount)
return sessionKeyAccount
} finally {
setIsLoading(false)
}
}
const registerUser = async (username: string) => {
setIsLoading(true)
try {
const { sessionKeyAccount } = await register(username, config)
setAccount(sessionKeyAccount)
return sessionKeyAccount
} finally {
setIsLoading(false)
}
}
const logoutUser = async () => {
await disconnect()
setAccount(null)
}
return {
account,
isLoading,
isAuthenticated: !!account,
login: loginUser,
register: registerUser,
logout: logoutUser,
}
}Error Handling
Common Error Types
try {
await register("username", config)
} catch (error) {
if (error.message.includes("User rejected")) {
// User cancelled passkey creation/authentication
console.log("Authentication cancelled by user")
} else if (error.message.includes("not supported")) {
// Browser doesn't support WebAuthn
console.log("Passkeys not supported in this browser")
} else if (error.message.includes("network")) {
// Network connectivity issues
console.log("Network error - please try again")
} else if (error.message.includes("already exists")) {
// Username already taken (for register)
console.log("Username already exists")
} else {
// Other errors
console.error("Authentication error:", error)
}
}Browser Compatibility
Passkey authentication requires modern browser support:
- Chrome: 67+
- Firefox: 60+
- Safari: 14+
- Edge: 18+
For unsupported browsers, consider showing a fallback message or alternative authentication method.
Security Considerations
- Username Privacy: Usernames are used for passkey creation but aren't stored on-chain
- Session Keys: Temporary keys are used for transactions to avoid repeated passkey prompts
- Local Storage: Authentication data is stored securely in browser storage
- Network Security: All communications use HTTPS and secure protocols