What is Base Verify?
Base Verify allows users to prove ownership of verified accounts (X, Coinbase, Instagram, TikTok) without sharing credentials. Your app receives a deterministic token for Sybil resistance. Even if a wallet has few transactions, Base Verify reveals whether the user is high-value through their verified social accounts (X Blue, Instagram, TikTok) or Coinbase One subscription. This lets you identify quality users regardless of onchain activity. Example use cases:- Token-gated airdrops or daily rewards
- Exclusive content access (e.g., creator coins)
- Identity-based rewards and loyalty programs
Core concepts
Provider
An identity platform that Base Verify integrates with. Currently supports X (Twitter), Coinbase, Instagram, and TikTok.Verification
Cryptographic proof that a wallet owns an account with a specific provider.Trait
A specific attribute of the provider account that can be verified. Examples:verified: true— X account has blue checkmarkcoinbase_one_active: true— active Coinbase One subscriptionfollowers: gt:1000— X account has over 1,000 followersfollowers_count: gte:5000— Instagram account with 5,000+ followersvideo_count: gte:50— TikTok account with 50+ videos
Action
A developer-defined string that identifies what the user is doing with their verification. Actions let you issue different tokens for different use cases within the same app. Examples:claim_daily_reward— claiming a daily rewardjoin_allowlist— joining an exclusive allowlistunlock_premium_content— accessing gated contentparticipate_in_raffle— entering a raffle
How actions work
Actions are specified in the SIWE message resources:Title
Title
Why actions matter
Different actions produce different tokens. This enables multiple independent claims from the same verified account:- User verifies X account with action
claim_airdrop→ Token:abc123 - Same X account with action
join_allowlist→ Token:def456(different) - Same X account with action
claim_airdropagain → Token:abc123(same as first)
- Multiple campaigns — run separate airdrops without interference
- Feature gating — different tokens for different premium features
- Time-based events — new action per event (e.g.,
raffle_jan_2025,raffle_feb_2025)
Choosing action names
Use descriptive, lowercase names with underscores:| Good | Bad |
|---|---|
claim_genesis_airdrop | airdrop (too generic) |
unlock_pro_features | action1 (meaningless) |
enter_weekly_raffle | base_verify_token (reserved/confusing) |
Token — Sybil resistance
A deterministic identifier tied to the provider account, not the wallet. This is the key anti-Sybil mechanism.How it works
- Wallet A verifies an X account → Base Verify returns
Token: abc123→ you have never seen it, so grant the airdrop. - The same X account tries again with Wallet B → Base Verify returns
Token: abc123→ you have seen it, so block the duplicate claim.
Token properties
- Deterministic — the same provider account always produces the same token
- Unique per provider — a user’s X token is different from their Instagram token
- Unique per app — your app receives different tokens than other apps (privacy)
- Action-specific — tokens vary based on the action in your SIWE message
- Persistent — tokens don’t expire or rotate (unless the user deletes their verification)
- Trait-independent — tokens stay the same even if traits change (e.g., follower count increases)
How to store tokens
Title
Prevent double claims
Title
Architecture and flow
Your app’s responsibilities
- Generate SIWE messages with trait requirements
- Handle user wallet connection
- Redirect to the Base Verify Mini App when verification is not found
- Store the returned verification token to prevent reuse
- Keep your secret key secure on the backend
Base Verify’s responsibilities
- Validate SIWE signatures
- Store provider verifications (X, Coinbase, Instagram, TikTok)
- Check if verification meets trait requirements
- Facilitate OAuth flow with providers
- Return deterministic tokens for Sybil resistance
Response codes
| Code | Meaning | Action |
|---|---|---|
| 200 OK | Wallet has verified the provider account AND meets all trait requirements. Returns a unique token. | Grant access, store the token. |
| 404 Not Found | Wallet has never verified this provider. | Redirect user to the Base Verify Mini App. |
400 Bad Request (verification_traits_not_satisfied) | Wallet has verified the provider, but doesn’t meet the trait requirements. | Show user they don’t meet requirements. Do not redirect. |
Getting started
Prerequisites
- API key — fill out the interest form to get access
- Wallet integration — users must be able to connect and sign messages
- Backend server — to securely call the Base Verify API
Register your app
Provide the Base Verify team:- Your Mini App domain
- Your redirect URI — where users return after verification (e.g.,
https://yourapp.com)
Implementation
Configure your app
Create a configuration file for your Base Verify integration:Add your secret key to
lib/config.ts
.env.local:.env.local
Generate the SIWE signature (frontend)
Build a SIWE message that includes the provider, trait requirements, and action:
lib/signature-generator.ts
Check verification (frontend → backend)
The frontend generates the signature and sends it to your backend, which calls the Base Verify API.Frontend:Backend (your API endpoint):
Title
pages/api/check-verification.ts
Error handling
| Response | What to do |
|---|---|
| 404 | User hasn’t verified. Redirect to the Base Verify Mini App. |
400 (verification_traits_not_satisfied) | User has account but doesn’t meet requirements. Show a message — don’t redirect and don’t retry. |
| 200 | Store the token and grant access. |
Do not retry 404 responses — the user simply hasn’t verified yet. Do not retry 400 responses with
verification_traits_not_satisfied — retrying won’t help unless the user’s account metrics change (e.g., they gain more followers).API reference
Authentication
All API requests require your secret key in theAuthorization header:
Title
POST /v1/base_verify_token
Check if a wallet has a specific verification and retrieve the verification token.Request
Title
Example request
Title
Responses
200 OK — verified:Title
| Field | Type | Description |
|---|---|---|
token | string | Deterministic verification token for Sybil resistance. Same provider account + same action = same token. |
action | string | The custom action specified in the SIWE message. Different actions produce different tokens. |
wallet | string | User’s wallet address. |
Title
Title
Title
Mini App redirect
To redirect users to Base Verify for verification:Title
| Parameter | Required | Description | Example |
|---|---|---|---|
redirect_uri | Yes | Where to send the user after verification | https://yourapp.com |
providers | Yes | Provider to verify | x, coinbase, instagram, tiktok |
Trait catalog
Traits are specific attributes of a provider account that you can verify. They are specified in SIWE message resources using this format:Title
Operations
| Operation | Symbol | Applies to | Description | Example |
|---|---|---|---|---|
| Equals | eq | All types | Exact match | verified:eq:true |
| Greater than | gt | Integers | Strictly greater | followers:gt:1000 |
| Greater/equal | gte | Integers | Greater or equal | followers:gte:1000 |
| Less than | lt | Integers | Strictly less | followers:lt:5000 |
| Less/equal | lte | Integers | Less or equal | followers:lte:5000 |
| In (list) | in | Strings | Value in comma-separated list | verified_type:in:blue,government |
Type system
Boolean traits:- Values:
"true"or"false"(as strings) - Only supports
eqoperation - Example:
verified:eq:true
- Values: numbers as strings
- Supports:
eq,gt,gte,lt,lte - Example:
followers:gte:1000
- Values: text strings
- Supports:
eq,in - Example:
verified_type:eq:blueorverified_type:in:blue,government
Combining traits
When you specify multiple traits for the same provider, all must be satisfied (AND logic):Title
You can only check one provider per request. To check multiple providers, make separate API calls.
Common patterns
Tiered access:Title
Coinbase
Provider:coinbase
| Trait | Type | Operations | Description | Example values |
|---|---|---|---|---|
coinbase_one_active | Boolean | eq | Active Coinbase One subscription | "true", "false" |
coinbase_one_billed | Boolean | eq | User has been billed for Coinbase One | "true", "false" |
Title
X (Twitter)
Provider:x
| Trait | Type | Operations | Description | Example values |
|---|---|---|---|---|
verified | Boolean | eq | Has any type of verification | "true", "false" |
verified_type | String | eq | Type of verification | "blue", "government", "business", "none" |
followers | Integer | eq, gt, gte, lt, lte | Number of followers | "1000", "50000" |
Title
instagram
| Trait | Type | Operations | Description | Example values |
|---|---|---|---|---|
username | String | eq | Instagram username | "john_doe" |
followers_count | Integer | eq, gt, gte, lt, lte | Number of followers | "1000", "50000" |
instagram_id | String | eq | Unique Instagram user ID | "1234567890" |
Title
TikTok
Provider:tiktok
| Trait | Type | Operations | Description | Example values |
|---|---|---|---|---|
open_id | String | eq | TikTok Open ID (unique per app) | "abc123..." |
union_id | String | eq | TikTok Union ID (unique across apps) | "def456..." |
display_name | String | eq | TikTok display name | "John Doe" |
follower_count | Integer | eq, gt, gte, lt, lte | Number of followers | "1000", "50000" |
following_count | Integer | eq, gt, gte, lt, lte | Number of accounts following | "500", "2000" |
likes_count | Integer | eq, gt, gte, lt, lte | Total likes received | "10000", "100000" |
video_count | Integer | eq, gt, gte, lt, lte | Number of videos posted | "50", "200" |
Title
Security and privacy
SIWE signature requirement
Every API call requires a valid SIWE signature from the wallet owner. This prevents:- Arbitrary lookup of verification status
- Third parties checking if a wallet is verified
- Enumeration attacks
Title
Validate trait requirements
Example attack without validation:- Your app requires users to have 100 followers
- User modifies the frontend to request only 10 followers
- User signs the modified message
- Without validation, your backend forwards the request to Base Verify
- User gains access with fewer than 100 followers
Title
Protect your secret key
Never:- Include the secret key in frontend code
- Use
NEXT_PUBLIC_*or similar environment variables that expose to the browser - Commit secret keys to version control
- Share secret keys in chat, email, or documentation
- Store the secret key in backend environment variables only
- Use
.envfiles that are gitignored - Rotate keys immediately if accidentally exposed
- Call the Base Verify API only from your backend
OAuth security model
Base Verify validates provider accounts through OAuth:- User initiates OAuth in the Base Verify Mini App
- Provider (X, Instagram, etc.) authenticates the user
- Provider returns an OAuth token to Base Verify
- Base Verify fetches account data using the OAuth token
- Base Verify stores the verification linked to the user’s wallet
- OAuth token is encrypted and stored securely
Data storage
What Base Verify stores:- Wallet addresses associated with verified provider accounts
- Provider account metadata (username, follower counts, verification status)
- OAuth tokens (encrypted, never shared with apps)
- Verification timestamps
- Users’ private keys
- Provider account passwords
- User activity or browsing history
- Any data beyond what’s needed for verification
/v1/base_verify_token, you receive only token, action, and wallet. No PII is returned.
User control
Users can delete their verifications at any time:- Removes all stored provider data
- Invalidates future token generation
- Your app’s stored tokens become meaningless (user can’t re-verify with the same account)
Caching
Cache verification results to reduce API calls:- Cache for the user’s session (not permanently)
- Clear cache when the user disconnects their wallet
- Don’t check verification on every page load