Skill 18 · Mapbox Token Security
Subchapter 18.4
AGENTS.mdMarkdown6 KBView on GitHub
Quick reference for securing Mapbox access tokens. Critical security rules for token management.
| Type | Format | Use | Can Expose? |
|---|---|---|---|
| Public | pk.* | Client-side, mobile apps | ✅ Yes (with URL restrictions) |
| Secret | sk.* | Server-side only | ❌ NEVER expose |
| Temporary | tk.* | One-time operations | ✅ Yes (expires in 1hr) |
// ❌ NEVER commit tokens
const MAPBOX_TOKEN = 'pk.eyJ1...'; // Don't hardcode!
// ❌ NEVER use secret tokens client-side
<script>mapboxgl.accessToken = 'sk.eyJ1...'; // Exposed to users!</script>;
// ❌ NEVER log tokens
console.log('Token:', token); // Shows in browser console
// ❌ NEVER share tokens in public repos
// .env file committed to GitHub// ✅ Use environment variables
const MAPBOX_TOKEN = process.env.NEXT_PUBLIC_MAPBOX_TOKEN;
// ✅ Add URL restrictions to public tokens
// In Mapbox dashboard: Restrict to your domain(s)
// ✅ Use secret tokens only server-side
// server.js or API routes only
// ✅ Add .env to .gitignore
// .gitignore
.env
.env.localQuestion 1: Where will this token be used?
Question 2: What operations are needed?
styles:tiles, styles:read✅ styles:tiles - Display raster style tiles
✅ styles:read - Read style specifications
✅ fonts:read - Access Mapbox fonts
✅ datasets:read - Read dataset data⚠️ styles:write - Create/modify styles
⚠️ styles:list - List all styles
⚠️ tokens:write - Create/modify tokens
⚠️ uploads:write - Upload dataPrinciple: Grant minimum scopes needed. Don’t use styles:write if only reading.
For all public tokens, always add URL restrictions:
http://localhost:* # Development
https://yourdomain.com/* # Production
https://*.yourdomain.com/* # SubdomainsImpact: Prevents token abuse if exposed. Must do for production.
# .env.local (Next.js, Vite)
NEXT_PUBLIC_MAPBOX_TOKEN=pk.your_token_here
VITE_MAPBOX_TOKEN=pk.your_token_here
# .env (Create React App)
REACT_APP_MAPBOX_TOKEN=pk.your_token_here// iOS (Config.xcconfig)
MAPBOX_TOKEN = pk.your_token_here;
// Android (gradle.properties)
MAPBOX_TOKEN = pk.your_token_here;Always add to .gitignore:
.env
.env.local
.env.*.localWhen to rotate:
How to rotate safely:
Risk: Anyone can use your token, rack up charges Fix: Immediately rotate token, add to .gitignore, use git history rewrite if needed
Risk: Token can be used on any domain Fix: Add URL restrictions in dashboard immediately
Risk: Full API access exposed to all users Fix: Move to server-side, rotate token immediately
Risk: Token can do more than needed Fix: Create new token with minimum required scopes
If token is exposed publicly:
Don’t wait - exposed tokens can be used within minutes.
✅ Using public tokens (pk.) for client-side? ✅ URL restrictions added to all public tokens? ✅ No tokens hardcoded in source code? ✅ .env files in .gitignore? ✅ Secret tokens (sk.) only used server-side? ✅ Minimum scopes granted per token? ✅ Tokens rotated regularly (90 days)? ✅ No tokens in logs or console output? ✅ Different tokens for dev/staging/production? ✅ Team members have individual tokens (not shared)?
// Public token (client-side)
const token = process.env.NEXT_PUBLIC_MAPBOX_TOKEN;
// Secret token (server-side API routes only)
const secretToken = process.env.MAPBOX_SECRET_TOKEN;// Must use REACT_APP_ prefix
const token = process.env.REACT_APP_MAPBOX_TOKEN;// Must use VITE_ prefix
const token = import.meta.env.VITE_MAPBOX_TOKEN;Free tier limits:
Best practices:
If approaching limits: Upgrade plan or optimize caching.