Skip to content

Token Gating

Token gating restricts access based on proof of on-chain token or NFT ownership: you only pass if the wallet you authenticate with holds what the gate requires. On Smart Engines this is one mechanism — the TokenGate — applied at distinct boundaries, with all the actual checking delegated to the Rules Engine.


It delegates to the rules engine — there is no standalone gate

Section titled “It delegates to the rules engine — there is no standalone gate”

The most important thing to understand for an audit: TokenGate is not a self-contained checker. It is a thin layer over the rules engine.

  • The canonical configuration shape is a TokenGate molecule in the rules engine — a validated schema of fungible and non-fungible requirements with AND/OR operators, optional serial numbers, balance ranges, and time/snapshot atoms.
  • The gate helper builds that molecule from the caller’s configuration and hands it to the rules engine, which runs it through the per-chain rule adapter for the caller’s chain. Balance and NFT lookups live in those adapters, not in the gate.
  • Token gates can also be written into a published rule. Those rules are public on HCS, and every validator checks them before it contributes a signature share: the operation’s subject must hold each gated token, and at least the stated balance of each fungible one.
%%{init: {'flowchart':{'htmlLabels':true,'curve':'basis'}}}%%
flowchart LR
    Caller["Auth caller<br/>(SDK or BaaS)"] --> Svc["Gate helper"]
    Svc -->|"builds TokenGate molecule"| RE["Rules engine"]
    RE --> Ad["Per-chain rule adapter"]
    Ad --> Chain[("On-chain<br/>balance / NFT lookup")]
    Chain --> RE
    RE -->|"satisfied?"| Svc
    Svc -->|"no → 403"| Caller

%%{init: {'flowchart':{'htmlLabels':true}}}%%
flowchart TB
    subgraph FaceA["Face A — SDK → Validator (platform-fixed)"]
      You["You, the builder"] -->|sign challenge with wallet key| Val["Validator auth"]
      Val -->|"signature valid → session"| You
      Val -.->|"HSUITE NFT check<br/>built, not yet enabled"| Val
    end
    subgraph FaceB["Face B — Customer → Smart App (you configure)"]
      Cust["Your customer"] -->|login| App["Your Smart App BaaS auth"]
      App -->|"holds your subscription NFT? → that tier<br/>otherwise → free tier"| Cust
    end

Both faces build the same TokenGate molecule and evaluate it through the rules engine’s per-chain adapters. The difference is which identity is checked and who owns the configuration.

Face A — you, authenticating to the validator (platform-fixed)

Section titled “Face A — you, authenticating to the validator (platform-fixed)”

When you (the builder, via the SDK) authenticate to the validator network, the validator checks your signed challenge and issues a session.

  • Designed requirement: an HSUITE NFT on XRPL. HSUITE and its subscription NFTs are XRPL-native, and the platform gate is meant to require holding the platform-membership NFT.
  • Status: built, not yet enabled. The gate is off unless the validator’s deployment turns it on, and the deployment does not turn it on today. When it is on, a requirement on a chain other than the one you sign in with cannot be met, and a request that matches no requirement on your chain is refused.

This is the platform’s own membership policy — you don’t write config for it.

Face B — your customers, authenticating to your app (you configure)

Section titled “Face B — your customers, authenticating to your app (you configure)”

When your customers sign in to your Smart App, the host resolves their subscription for your app at login:

  1. If your app has an XRPL subscription issuer, the host checks the TokenGate for your app’s subscription NFT against the customer’s address.
  2. If the customer holds one, the host reads the NFT’s metadata (tier, expiry, allowed automations) and stamps that tier into the customer’s session.
  3. If the app has no issuer, the gate is not met, or any lookup fails, the customer is on the free tier. Login itself still succeeds.

Your customers do not need an HSUITE NFT; they need whatever your app issues. On the host, only the XRPL rule adapter is wired today, so a customer gate can be met only on XRPL; a requirement on another chain is never satisfied.

Full Face-B configuration is documented in the TokenGate smart-app guide.


When the platform gate’s requirements are not met, sign-in fails with a 403 whose message names the reason:

{
"statusCode": 403,
"error": "Forbidden",
"message": "Token gate requirements not met: ..."
}

  1. Verify on-chain, not from cached metadata — adapters query ledger state when the gate is evaluated. On the host, a gate result is cached for 60 seconds, so a token that moves is reflected within that window.
  2. Tokens can move between checks — a customer’s tier is resolved at login and carried in the session, so combine gates with session timeouts to force re-verification.
  3. Rules are public — a token gate written into a published rule is on HCS, so a misconfigured rule gate is auditable, not hidden. Treat the rule set as the security boundary.
  4. Rate-limit the verification path — prevent abuse of the auth endpoint.