Skip to content
LogoLogo

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 object

Example:

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 object

Example:

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 address

Example:

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

  1. Check listener registration: Ensure listeners are registered before triggering actions
  2. Verify imports: Make sure you're importing from @openfort/openfort-js
  3. Check cleanup: Ensure you're not removing listeners prematurely

Memory leaks

If you notice memory issues:

  1. Always clean up listeners in useEffect cleanup or componentWillUnmount
  2. Use removeAllListeners for the specific event, not globally
  3. Consider using weak references for long-lived listeners