Token Gating

Token Gating

Magic's SDKs allow developers to create allow lists based on NFTs owned by a user -- also known as token gating. This functionality can enable exclusive events, experiences, and digital content accessed only by holders of specific NFTs. You can restrict sections of websites, verify tickets at in-person events, and much more!

#Use Cases

Magic's Token Gating can be used any time you want to determine if someone holds a specific NFT in their wallet and take some action / restrict some action based on that:

  • Ticketing at a live event
  • Restricted areas of websites
  • Members-only swag drops

Magic's Token Gating is compatible with both Magic wallets and all third party wallets (e.g., MetaMask, Coinbase Wallet).


Magic's Token Gating works by validating a user's ownership of a crypto wallet and then checking if an NFT from a specific collection is stored in that wallet.

We have a Demo Repo with a fully functioning token gating website that you can run locally and deploy to Vercel.


1. Get the NFT smart contract address of the NFT collection with which you are token gating.

Note: That could be an existing collection (like the NFTs available to mint for free on Magic's homepage) or a collection you create yourself. If you want to create your own NFT collection for users, Magic offers several NFT-related services from NFT Smart Contract Creation to Minting and Checkout.

2. Generate a DID token for the user, in order to verify their identiy on the backend.

For users that are logged into Magic you can use the `getIdToken()` function:

01import { Magic } from "magic-sdk"
03const magic = new Magic(MAGIC_API_KEY);
04const token = await magic.user.getIdToken();

For third party wallets, you will need to generate a DID token manually. You will need to set the `audience` or `aud` field to be the Client ID for the Magic App you are using -- you can find this at in the URL query param `cid=`:

01export async function createDIDToken(options: {
02  account: { address: string; privateKey?: string };
03  subject: string;
04  audience: string;
05  lifespan: number;
06  attachment?: string;
07  systemClockOffset?: number;
08}): Promise<string> {
09  const { account, subject, audience, lifespan, attachment, systemClockOffset = 0 } = options;
10  const utcTimeSecs = Math.floor( / 1000) + Math.floor(systemClockOffset / 1000);
12  const claim = JSON.stringify({
13    iat: utcTimeSecs,
14    ext: utcTimeSecs + lifespan,
15    iss: generateUserId(account.address),
16    sub: subject,
17    aud: audience,
18    nbf: utcTimeSecs,
19    tid: uuid(),
20    add: Web3Service.personalSign(attachment || 'none', account.privateKey),
21  });
23  // The final token is an encoded string containing a JSON tuple: [proof, claim]
24  // proof should be a signed claim, if correct.
25  const proof = Web3Service.personalSign(claim, account.privateKey);
26  return encodeBase64(JSON.stringify([proof, claim]));

3. Call the Magic Admin SDK function on your backend to validate the token and check if the user owns the NFT:

01import { Magic } from '@magic-sdk/admin';
03const magic = new Magic(MAGIC_SECRET_KEY);
04const isValid = await magic.utils.validateTokenOwnership(
05    'abcd1234', // DID token
06    '0xABCD', // NFT smart contract address
07    'ERC1155', // either ERC1155 or ERC721
08    '', // The RPC url for your web3 provider
09    1, // (optional) tokenId if using ERC1155

4. Redirect your users or provide new content based on whether the validation is successful!

#In-Person Events

To use token gating to manage access for in-person events, you can provide users with a QR code or link (for example in an email) to your website, prompting the user to validate ownership of their wallet. Once the user successfully validates ownership, this should generate a dynamic QR code representing the DID token.

Users can present this QR code to event staff, who would scan it with an app or website and call the same Magic Admin SDK `validateTokenOwnership` function to check whether the ticket is valid.

Token Gating