Use this file to discover all available pages before exploring further.
Message signing allows users to cryptographically prove their identity and provide data without paying transaction fees. This makes it perfect for authentication, feedback collection, surveys, and any scenario where you need verified user input but don’t require on-chain storage.
Simple message signing with a static string. Best for basic authentication and use-cases where you don’t need the enhanced security of the structured approach.
src/app/api/actions/sign-plain/route.ts
import { ActionGetResponse, ActionPostRequest, ActionPostResponse, ActionError, ACTIONS_CORS_HEADERS, BLOCKCHAIN_IDS} from "@solana/actions";import { PublicKey } from "@solana/web3.js";import nacl from "tweetnacl";import * as bs58 from "bs58";const blockchain = BLOCKCHAIN_IDS.mainnet;const headers = { ...ACTIONS_CORS_HEADERS, 'X-Blockchain-Ids': blockchain, 'X-Action-Version': '2.4'};// The message users will signconst MESSAGE = "Please sign this message to verify your wallet";export const OPTIONS = async () => new Response(null, { headers });export const GET = async (req: Request) => { const payload: ActionGetResponse = { type: "action", icon: new URL("/sign-icon.jpg", req.url).toString(), title: "Sign Message Demo", description: "Sign a message to verify your wallet ownership", label: "Sign Message", links: { actions: [ { type: "message", // Use 'message' type instead of 'transaction' href: "/api/actions/sign-plain", label: "Sign Message" } ] } }; return new Response(JSON.stringify(payload), { headers });};export const POST = async (req: Request) => { try { const request: ActionPostRequest = await req.json(); const { account, signature } = request; if (!signature) { const error: ActionError = { message: "Signature is required for verification" }; return new Response(JSON.stringify(error), { status: 400, headers }); } // Verify the signature const isValid = verifySignature(MESSAGE, signature, account); if (!isValid) { const payload: ActionGetResponse = { type: "action", icon: new URL("/sign-icon.jpg", req.url).toString(), title: "❌ Signature Invalid", description: `Invalid signature for account: ${account}`, label: "Try Again", links: { actions: [] } }; return new Response(JSON.stringify(payload), { headers }); } // Success response const payload: ActionGetResponse = { type: "action", icon: new URL("/sign-icon.jpg", req.url).toString(), title: "✅ Signature Verified", description: `Successfully verified signature for: ${account}`, label: "Completed", links: { actions: [] } }; return new Response(JSON.stringify(payload), { headers }); } catch (error) { console.error("Signature verification error:", error); const errorResponse: ActionError = { message: "Failed to verify signature" }; return new Response(JSON.stringify(errorResponse), { status: 500, headers }); }};// Signature verification utilityfunction verifySignature(message: string, signature: string, account: string): boolean { try { const messageBytes = new TextEncoder().encode(message); const signatureBytes = bs58.decode(signature); const publicKeyBytes = new PublicKey(account).toBytes(); return nacl.sign.detached.verify( messageBytes, signatureBytes, publicKeyBytes ); } catch { return false; }}
Uses the SIWS (Sign-In With Solana) standard with anti-replay protection and domain binding. Best for production applications requiring enhanced security.