I am building a Solana program using Anchor and I would like to know which is the recommended way to authenticate/validate users allowed to execute certain Solana instructions. For what I have seen so far the Metaplex Token metadata program provides the NFT metadata required to validate the NFTs, but I couldn't find examples on Solana's cookbook.
2 Answers
Manual implementations
A brief question that calls for an in-depth answer, I think this has been asked many times before:
Using Sol Cerberus (recommended)
Probably the quickest implementation and the most reliable option at the moment is using Sol Cerberus, an on-chain Solana authentication program funded by the Solana Foundation which allows you to create access rules and assign roles to the users of your program through a simple user interface.
Integration
The integration is pretty straightforward and explained in the docs. In a nutshell you just need to do three things:
- Assign roles to your users (to their wallets or NFTs)
- Add rules (grant permissions to the assigned roles)
- Add the corresponding rule to the instructions of your Anchor program to limit the access.
Taking the SC demo program as an example, for creating a square it uses the Add
permission on the Square
resource. Therefore only the roles with the Square -> Add
permission will be allowed to execute the instruction:
# RUST
use sol_cerberus_macros::rule;
declare_id!("THE_PROGRAM_ID");
#[program]
pub mod sol_cerberus_demo {
use super::*;
#[rule(Square, Add)]
pub fn add_square(ctx: Context<Add>, color: String, size: u16) -> Result<()> {
instructions::add::add(ctx, "square", &color, size)
}
}
and in the frontend:
// Javascript
let solCerberus = new SolCerberus(connection, myWallet);
await myProgram.methods.addSquare(color, size)
.accounts({
demo: pdas.demoPda,
...(await solCerberus.accounts("Square", "Add")),
})
.rpc();
This is the way to validate the wallet address.
#[account(mut, constraint = signer.key() == "GEPxxxxx...".parse::<Pubkey>().unwrap())]
pub signer: Signer<'info>
This is way to verify NFT. As you know to verify the nft on Solana, we can use the creator address.
let nft_metadata = Metadata::from_account_info(mint_metadata)?;
if let Some(creators) = nft_metadata.data.creators {
let mut valid: u8 = 0;
for creator in creators {
if creator.address == CREATOR.parse::<Pubkey>().unwrap() && creator.verified == true
{
valid = 1;
break;
}
}
if valid != 1 {
return Err();
}
} else {
return Err();
};