Forest Docs
DevelopersForest Playkit

Player Identity

Wallet messages and trusted player identity code redemption.

Project and Wallet Messages

Forest sends project and wallet messages to your iframe. Your app can also request the latest wallet state.

MessageDirectionPurpose
FOREST_PROJECT_CONTEXTForest to iframeProvides the active Forest project id and auto-swap availability.
FOREST_REQUEST_WALLETiframe to ForestAsk Forest to send the current wallet state.
FOREST_WALLET_CONNECTEDForest to iframeDisplay-only connected wallet address. See the warning below.
FOREST_WALLET_DISCONNECTEDForest to iframeTells your app that no wallet is connected.

Request the current wallet state:

JavaScript
window.parent.postMessage({ type: "FOREST_REQUEST_WALLET" }, "*");

Handle wallet state:

JavaScript
window.addEventListener("message", (event) => {
	if (event.source !== window.parent) return;

	const data = event.data || {};

	if (data.type === "FOREST_WALLET_CONNECTED") {
		wallet = data.walletAddress;
	}

	if (data.type === "FOREST_WALLET_DISCONNECTED") {
		wallet = null;
	}
});

Only the project id and public wallet address are exposed. Forest does not send auth tokens, private keys, cookies, or session data to the iframe.

FOREST_WALLET_CONNECTED is display-only

The address is fine for rendering (greetings, avatars), but it is not an authenticated credential. Once it reaches your uploaded HTML it is a plain string the player can rewrite in their own browser and report to your backend. Never use this address for backend identity or accounting. To learn the verified player identity, use the Player Identity flow below.

Player Identity

When your trusted backend needs to know which Forest player is in the session — to key accounting, anti-abuse, or per-player state — do not trust the wallet message. Run a one-time server-to-server handshake instead. The identity code carries no data and grants no spend authority; it is only a lookup key your backend redeems with the same Settlement Signing Secret HMAC it already uses for settlement.

The identity handshake

Mint a single-use nonce (your backend)

Your backend mints a single-use nonce for this login attempt and stores it. The nonce binds the identity to one login transaction and is verified on redeem.

Request a code from the iframe

The iframe calls forest.identity.code({ nonce }) with that nonce. Forest returns { code, expiresAt }.

Relay the code to your backend

The iframe relays the opaque code to your backend. The code carries no identity data — do not log it or put it in URLs.

Redeem the code (your backend)

Your backend redeems the code against Forest with the HMAC-signed request, getting back { userId, walletAddress, nonce, issuedAt }.

Assert the nonce matches

Your backend asserts the returned nonce equals the unconsumed nonce you minted for this login, then burns it.

Mint your session

Only after the nonce check passes does your backend mint its own session, keyed on the verified userId.

forest.identity.code

Issues a short-lived (60s), single-use identity code for the authenticated player session.

JavaScript
callForest("forest.identity.code", {
	// Required. A single-use nonce your backend minted for this login attempt and
	// will verify is echoed on redeem. Binds the identity to one login transaction.
	nonce,
});
// The { code, expiresAt } response arrives via your FOREST_RPC_RESPONSE listener.

The code is opaque and contains no identity data. Relay it to your backend; do not log it or put it in URLs.

Redeem (trusted backend only)

HTTP
POST /campaigns/{projectId}/html/identity/redeem
X-Forest-Settlement-Signature: v1=<hmac-sha256 of the raw body>

Request fields:

Prop

Type

Sign and send exactly like a settlement (reuse your settlement signing helper):

JavaScript
const body = JSON.stringify({ code, timestamp: Math.floor(Date.now() / 1000) });
const signature = `v1=${createHmac("sha256", SETTLEMENT_SIGNING_SECRET).update(body).digest("hex")}`;

const res = await fetch(`${FOREST_API}/campaigns/${projectId}/html/identity/redeem`, {
	method: "POST",
	headers: { "Content-Type": "application/json", "X-Forest-Settlement-Signature": signature },
	body,
});
// { userId, walletAddress, nonce, issuedAt }

Rules that matter:

  • Derive {projectId} from your own server config, never from the frontend-relayed value.
  • Assert the returned nonce equals the unconsumed nonce you minted for this login, then burn it.
  • Key accounting on userId (immutable). Treat walletAddress as a verified display/payout reference.
  • The code is single-use. A second redeem is rejected and the code must not be cached. See Identity errors.
  • If the redeem response is lost (network blip after Forest consumed the code), do not retry the redeem — it will fail as consumed. Recover by issuing a fresh code (restart at login).