Openfort SDK events
The Openfort SDK provides an event system that allows you to monitor and respond to authentication, wallet, and UI lifecycle events in your application.
Event system overview
The SDK uses a typed event emitter that you can access via the openfortEvents export. All events are strongly typed and provide detailed payload information.
import { openfortEvents, OpenfortEvents } from '@openfort/openfort-js'
// Subscribe to an event
openfortEvents.on(OpenfortEvents.ON_AUTH_SUCCESS, (authResponse) => {
console.log('User authenticated:', authResponse.user.id)
})
// Remove a specific listener
const handler = (authResponse) => console.log('Auth success')
openfortEvents.on(OpenfortEvents.ON_AUTH_SUCCESS, handler)
openfortEvents.off(OpenfortEvents.ON_AUTH_SUCCESS, handler)
// Remove all listeners for an event
openfortEvents.removeAllListeners(OpenfortEvents.ON_AUTH_SUCCESS)Authentication events
ON_AUTH_INIT
Called when an authentication process begins, before the user completes authentication.
Payload:
type AuthInitPayload = {
method: 'email' | 'oauth' | 'siwe' | 'idToken' | 'guest' | 'phone'
provider?: string // OAuth provider name (for example, 'google', 'discord')
}Example:
openfortEvents.on(OpenfortEvents.ON_AUTH_INIT, (payload) => {
console.log(`Authentication started with ${payload.method}`)
if (payload.provider) {
console.log(`Using provider: ${payload.provider}`)
}
// Show loading indicator, track analytics, etc.
})Use cases:
- Display loading states
- Track authentication attempts in analytics
- Log authentication method usage
ON_AUTH_SUCCESS
Called after the user successfully authenticates and receives a session token.
Payload:
type AuthResponse = {
token: string | null // Session token for authentication
user: User // User profile information
session?: Session // Optional session details
}
type User = {
id: string // Unique user identifier
email?: string // User's email address
name?: string // User's display name
image?: string // URL to user's profile image
emailVerified?: boolean // Whether email has been verified
createdAt?: string // ISO timestamp when created
updatedAt?: string // ISO timestamp when last updated
isAnonymous?: boolean // Whether user is anonymous (guest)
phoneNumber?: string // User's phone number
phoneNumberVerified?: boolean // Whether phone has been verified
linkedAccounts?: UserAccount[] // Linked authentication accounts
}Example:
openfortEvents.on(OpenfortEvents.ON_AUTH_SUCCESS, (authResponse) => {
console.log('User authenticated successfully!')
console.log('User ID:', authResponse.user.id)
console.log('Email:', authResponse.user.email)
router.push('/dashboard')
})Use cases:
- Navigate user to authenticated area
- Store user preferences
- Initialize user-specific features
- Track successful authentication in analytics
ON_AUTH_FAILURE
Called when authentication fails due to an error.
Payload:
Error // Standard JavaScript Error objectExample:
openfortEvents.on(OpenfortEvents.ON_AUTH_FAILURE, (error) => {
console.error('Authentication failed:', error.message)
// Show error message to user
toast.error(`Failed to authenticate: ${error.message}`)
// Track error in monitoring
Sentry.captureException(error)
})Use cases:
- Display error messages to users
- Log authentication errors
- Retry authentication logic
- Error tracking and monitoring
ON_LOGOUT
Called after the user successfully logs out.
Payload: None
Example:
openfortEvents.on(OpenfortEvents.ON_LOGOUT, () => {
console.log('User logged out')
// Clear local state, navigate to login, etc.
localStorage.clear()
router.push('/login')
})Use cases:
- Clear local application state
- Navigate to login page
- Reset UI components
- Clear sensitive data from memory
ON_OTP_REQUEST
Called when an OTP (one-time passcode) is requested for email or phone authentication.
Payload:
{
method: 'email' | 'phone'
provider?: string // For phone OTP, this is 'phone'
}Example:
openfortEvents.on(OpenfortEvents.ON_OTP_REQUEST, (payload) => {
console.log(`OTP requested via ${payload.method}`)
// Show OTP input form
showOtpInputForm()
})Use cases:
- Display OTP input form
- Start countdown timer for resend
- Track OTP request attempts
ON_OTP_FAILURE
Called when an OTP request fails.
Payload:
Error // Standard JavaScript Error objectExample:
openfortEvents.on(OpenfortEvents.ON_OTP_FAILURE, (error) => {
console.error('OTP request failed:', error.message)
toast.error('Failed to send OTP. Please try again.')
})Use cases:
- Display error messages
- Handle rate limiting
- Retry OTP request
Wallet events
ON_EMBEDDED_WALLET_CREATED
Called after a new embedded wallet is created for the user.
Payload:
type EmbeddedAccount = {
id: string
user: string
address: string
chainId?: number
chainType: 'EVM' | 'SVM'
accountType: 'Externally Owned Account' | 'Smart Account' | 'Delegated Account'
ownerAddress?: string
implementationType?: string
implementationAddress?: string
factoryAddress?: string
salt?: string
createdAt?: number
recoveryMethod?: 'password' | 'automatic' | 'passkey'
recoveryMethodDetails?: {
passkeyId?: string
passkeyEnv?: {
name?: string
os?: string
osVersion?: string
device?: string
}
}
}Example:
openfortEvents.on(OpenfortEvents.ON_EMBEDDED_WALLET_CREATED, (wallet) => {
console.log('New wallet created!')
console.log('Address:', wallet.address)
console.log('Chain ID:', wallet.chainId)
console.log('Account type:', wallet.accountType)
console.log('Recovery method:', wallet.recoveryMethod)
// Display wallet address to user
setWalletAddress(wallet.address)
// Track wallet creation
analytics.track('wallet_created', {
chainType: wallet.chainType,
accountType: wallet.accountType,
})
})Use cases:
- Display new wallet information
- Store wallet address in UI state
- Track wallet creation metrics
- Initialize wallet-dependent features
ON_EMBEDDED_WALLET_RECOVERED
Called when an existing embedded wallet is recovered.
Payload:
type EmbeddedAccount = {
// Same structure as ON_EMBEDDED_WALLET_CREATED
}Example:
openfortEvents.on(OpenfortEvents.ON_EMBEDDED_WALLET_RECOVERED, (wallet) => {
console.log('Wallet recovered!')
console.log('Address:', wallet.address)
console.log('Recovery method used:', wallet.recoveryMethod)
// Update UI with recovered wallet
setWalletAddress(wallet.address)
// Track recovery
analytics.track('wallet_recovered', {
recoveryMethod: wallet.recoveryMethod,
})
})Use cases:
- Display recovered wallet information
- Track successful wallet recovery
- Verify recovery method
- Resume wallet operations
ON_SWITCH_ACCOUNT
Called when switching between different accounts or chains.
Payload:
string // The new account addressExample:
openfortEvents.on(OpenfortEvents.ON_SWITCH_ACCOUNT, (address) => {
console.log('Switched to account:', address)
// Update UI with new account
setCurrentAccount(address)
// Refresh account balance
fetchBalance(address)
// Update chain-specific components
updateChainInfo()
})Use cases:
- Update UI when user switches accounts
- Refresh account-specific data
- Update balance displays
- Sync with blockchain state
ON_SIGNED_MESSAGE
Called whenever the wallet signs a message. This includes:
- Personal message signing (
signMessage) - Typed data signing (
signTypedData/ EIP-712) - Transaction signatures
- Session key signatures
- Internal signing operations
Payload:
type SignedMessagePayload = {
message: string | Uint8Array // The message that was signed
signature: string // The resulting signature (hex string)
}Example:
openfortEvents.on(OpenfortEvents.ON_SIGNED_MESSAGE, (payload) => {
console.log('Message signed!')
console.log('Message:', payload.message)
console.log('Signature:', payload.signature)
// Track signing activity
analytics.track('message_signed', {
messageLength: typeof payload.message === 'string'
? payload.message.length
: payload.message.length,
})
// Store signature for later use
saveSignature(payload.signature)
// Show success notification
toast.success('Message signed successfully!')
})Use cases:
- Track all signing operations
- Audit trail for signatures
- Display signing confirmations
- Monitor transaction signing
- Debug signing issues
- Implement custom signing workflows
Note: This event is emitted for ALL signing operations, including:
- Manual
openfort.signMessage()calls - EIP-712 typed data signing
- Smart account user operation signatures
- EOA transaction signatures
- Session key registration/revocation signatures
TypeScript types
All events are fully typed. Import the types you need:
import type {
OpenfortEvents,
OpenfortEventMap,
AuthInitPayload,
AuthResponse,
EmbeddedAccount,
SignedMessagePayload,
} from '@openfort/openfort-js'The OpenfortEventMap provides the complete type mapping:
interface OpenfortEventMap {
[OpenfortEvents.ON_AUTH_INIT]: [AuthInitPayload]
[OpenfortEvents.ON_AUTH_SUCCESS]: [AuthResponse]
[OpenfortEvents.ON_AUTH_FAILURE]: [Error]
[OpenfortEvents.ON_LOGOUT]: []
[OpenfortEvents.ON_OTP_REQUEST]: [{ method: 'email' | 'phone'; provider?: string }]
[OpenfortEvents.ON_OTP_FAILURE]: [Error]
[OpenfortEvents.ON_SWITCH_ACCOUNT]: [string]
[OpenfortEvents.ON_SIGNED_MESSAGE]: [SignedMessagePayload]
[OpenfortEvents.ON_EMBEDDED_WALLET_CREATED]: [EmbeddedAccount]
[OpenfortEvents.ON_EMBEDDED_WALLET_RECOVERED]: [EmbeddedAccount]
}Best practices
1. Always clean up listeners
Remove event listeners when components unmount to prevent memory leaks:
useEffect(() => {
const handler = (data) => console.log(data)
openfortEvents.on(OpenfortEvents.ON_AUTH_SUCCESS, handler)
return () => {
openfortEvents.off(OpenfortEvents.ON_AUTH_SUCCESS, handler)
}
}, [])2. Handle errors gracefully
Always handle the ON_AUTH_FAILURE event to provide user feedback:
openfortEvents.on(OpenfortEvents.ON_AUTH_FAILURE, (error) => {
// Show user-friendly error message
toast.error(getUserFriendlyError(error))
// Log for debugging
console.error('Auth error:', error)
// Track in error monitoring
Sentry.captureException(error)
})3. Use events for analytics
Events are perfect for tracking user behavior:
openfortEvents.on(OpenfortEvents.ON_AUTH_SUCCESS, (auth) => {
analytics.track('user_authenticated', {
user_id: auth.user.id,
is_anonymous: auth.user.isAnonymous,
})
})
openfortEvents.on(OpenfortEvents.ON_SIGNED_MESSAGE, () => {
analytics.track('message_signed')
})4. Avoid heavy operations in event handlers
Keep event handlers lightweight and asynchronous when needed:
openfortEvents.on(OpenfortEvents.ON_AUTH_SUCCESS, async (auth) => {
// Good: Non-blocking UI update
setUser(auth.user)
// Good: Async heavy operation doesn't block
fetchUserData(auth.user.id).catch(console.error)
})5. Type your event handlers
Use proper TypeScript types for type safety:
import type { AuthResponse, EmbeddedAccount } from '@openfort/openfort-js'
const handleAuthSuccess = (auth: AuthResponse) => {
console.log(auth.user.id) // Fully typed!
}
const handleWalletCreated = (wallet: EmbeddedAccount) => {
console.log(wallet.address) // Fully typed!
}
openfortEvents.on(OpenfortEvents.ON_AUTH_SUCCESS, handleAuthSuccess)
openfortEvents.on(OpenfortEvents.ON_EMBEDDED_WALLET_CREATED, handleWalletCreated)Troubleshooting
Events not firing
- Check listener registration: Ensure listeners are registered before triggering actions
- Verify imports: Make sure you're importing from
@openfort/openfort-js - Check cleanup: Ensure you're not removing listeners prematurely
Memory leaks
If you notice memory issues:
- Always clean up listeners in useEffect cleanup or componentWillUnmount
- Use
removeAllListenersfor the specific event, not globally - Consider using weak references for long-lived listeners