Skip to content

Securing Frames

There are a couple of things you can do to secure frames:

  1. Frame Data Verification
  2. Signing State

Frame Data Verification

When a frame responds to a POST request from a Farcaster Client, we may want to verify the body of the request against a Farcaster Hub to make sure that the contents of the frameData (such as buttonIndex, fid, castId, etc) legitimately belong to the user that interacted with it.

app.frame('/', (c) => {
  const { frameData } = c
  const { buttonIndex, fid, castId } = frameData
  return c.res({/* .... */})
})

The body of a POST request contains a signed message (trustedData), and an unsigned message (untrustedData), which is eventually converted to the frameData object in context. This may contain things like:

  • The index of the button clicked (buttonIndex)
  • Value of the text input (inputText)
  • The user's FID (fid)

To verify frames with Frog, we can utilize the verify flag on either the Frog instance, or the frame return object.

Supplying Hub Configuration

We can set Hub configuration to use for verification by providing it to the Frog instance.

Frog currently supports neynar as a built-in Hub.

import { Frog } from 'frog'
import { neynar } from 'frog/hubs'
 
export const app = new Frog({
  hub: neynar({ apiKey: 'NEYNAR_FROG_FM' }),
  title: 'Frog Frame',
})

You can also supply your own Hub API URL:

import { Frog } from 'frog'
 
export const app = new Frog({
  hub: { apiUrl: 'https://myhub.com' },
  title: 'Frog Frame',
})

Silent Verification

We can verify "silently" by setting the verify flag to "silent" on the Frog instance.

This means the frame will go through verification, but not throw an error if it fails. Instead, the frame will receive verified: false in its context.

import { Frog } from 'frog'
 
export const app = new Frog({
  verify: 'silent',
  title: 'Frog Frame',
})
 
app.frame('/', (c) => {
  const { frameData, verified } = c
  const { buttonIndex, fid, castId } = frameData
  if (!verified) console.log('Frame verification failed')
  return c.res({/* .... */})
})

Signing State

We can sign derived state (from deriveState) in a frame to ensure that state is not tampered with between frame actions.

Frog internally uses JSON Web Signatures (JWS) to sign state, with a HS256 algorithm.

If a secret is provided to the Frog instance, then state will be signed automatically.

src/index.ts
import { Frog } from 'frog'
 
const app = new Frog({
  secret: process.env.FROG_SECRET,
  title: 'Frog Frame',
})