Securing Frames
There are a couple of things you can do to secure frames:
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 a Hub API URL
We can set a custom Hub API URL to use for verification by providing it to the Frog
instance.
import { Frog } from 'frog'
export const app = new Frog({
hubApiUrl: 'https://api.hub.wevm.dev'
})
app.frame('/', (c) => {
const { frameData, verified } = c
const { buttonIndex, fid, castId } = frameData
if (!verified) console.log('Frame verification failed')
return c.res({/* .... */})
})
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'
})
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.
import { Frog } from 'frog'
const app = new Frog({
secret: process.env.FROG_SECRET
})