After a user signs a message using the Phantom Connect SDK, verify the signature on your backend to prove they own the wallet.Documentation Index
Fetch the complete documentation index at: https://docs.phantom.com/llms.txt
Use this file to discover all available pages before exploring further.
Get a signature (frontend)
First, have the user sign a message using the SDK:- React
- Browser SDK
- React Native
import { useSolana } from "@phantom/react-sdk";
function SignForVerification() {
const { solana } = useSolana();
const signAndVerify = async () => {
const message = "Hello, please sign this message";
// Sign the message using the SDK
const { signature } = await solana.signMessage(message);
// Send to your backend for verification
const response = await fetch("/api/verify", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
address: await solana.getPublicKey(),
message,
signature,
}),
});
const { verified } = await response.json();
console.log("Signature verified:", verified);
};
return <button onClick={signAndVerify}>Sign and Verify</button>;
}
import { BrowserSDK, AddressType } from "@phantom/browser-sdk";
const sdk = new BrowserSDK({
providers: ["google", "apple", "injected"],
appId: "your-app-id",
addressTypes: [AddressType.solana],
});
async function signAndVerify() {
const message = "Hello, please sign this message";
// Sign the message using the SDK
const { signature } = await sdk.solana.signMessage(message);
const address = await sdk.solana.getPublicKey();
// Send to your backend for verification
const response = await fetch("/api/verify", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ address, message, signature }),
});
const { verified } = await response.json();
return verified;
}
import { useSolana } from "@phantom/react-native-sdk";
import { View, Button, Alert, StyleSheet } from "react-native";
function SignForVerification() {
const { solana } = useSolana();
const signAndVerify = async () => {
try {
const message = "Hello, please sign this message";
const { signature } = await solana.signMessage(message);
const address = await solana.getPublicKey();
const response = await fetch("/api/verify", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
address,
message,
signature,
}),
});
const { verified } = await response.json();
if (verified) {
Alert.alert("Success", "Signature verified!");
} else {
Alert.alert("Error", "Signature verification failed");
}
} catch (error) {
Alert.alert("Error", error.message);
}
};
return (
<View style={styles.container}>
<Button title="Sign and Verify" onPress={signAndVerify} />
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 20,
},
});
Verify a signature (backend)
Install dependencies
npm install @solana/web3.js tweetnacl bs58
Verify a Solana signature
import { PublicKey } from "@solana/web3.js";
import nacl from "tweetnacl";
import bs58 from "bs58";
function verifySignature(
walletAddress: string,
message: string,
signature: string
): boolean {
try {
const publicKey = new PublicKey(walletAddress);
const messageBytes = new TextEncoder().encode(message);
const signatureBytes = bs58.decode(signature);
return nacl.sign.detached.verify(
messageBytes,
signatureBytes,
publicKey.toBytes()
);
} catch {
return false;
}
}
// Usage
const isValid = verifySignature(
"7fUAJdStEuGbc3sM84cKRL6yYaaSstyLSU4ve5oovLS7",
"Hello, please sign this message",
"5eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9..."
);
console.log("Signature valid:", isValid);
API route example (Next.js)
// app/api/verify/route.ts
import { PublicKey } from "@solana/web3.js";
import nacl from "tweetnacl";
import bs58 from "bs58";
import { NextResponse } from "next/server";
export async function POST(request: Request) {
const { address, message, signature } = await request.json();
try {
const publicKey = new PublicKey(address);
const messageBytes = new TextEncoder().encode(message);
const signatureBytes = bs58.decode(signature);
const isValid = nacl.sign.detached.verify(
messageBytes,
signatureBytes,
publicKey.toBytes()
);
if (!isValid) {
return NextResponse.json({ error: "Invalid signature" }, { status: 401 });
}
return NextResponse.json({ verified: true, address });
} catch (error) {
return NextResponse.json({ error: "Verification failed" }, { status: 400 });
}
}