Installs into .claude/skills of the current project.
Are you the author of Supabase Extract Anon Key?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/yoanbernabeu-supabase-extract-anon-key)
---
name: supabase-extract-anon-key
description: Extract the Supabase anon/public API key from client-side code. This key is expected in client apps but important for RLS testing.
---
# Supabase Anon Key Extraction
> ๐ด **CRITICAL: PROGRESSIVE FILE UPDATES REQUIRED**
>
> You MUST write to context files **AS YOU GO**, not just at the end.
> - Write to `.sb-pentest-context.json` **IMMEDIATELY after each discovery**
> - Log to `.sb-pentest-audit.log` **BEFORE and AFTER each action**
> - **DO NOT** wait until the skill completes to update files
> - If the skill crashes or is interrupted, all prior findings must already be saved
>
> **This is not optional. Failure to write progressively is a critical error.**
This skill extracts the Supabase anonymous (public) API key from client-side code.
## When to Use This Skill
- After extracting the Supabase URL, to get the API key for testing
- To verify that only the anon key (not service key) is exposed
- Before running API audit skills that require authentication
## Prerequisites
- Supabase URL extracted (or will auto-invoke `supabase-extract-url`)
- Target application accessible
## Understanding Anon Keys
The **anon key** (also called public key) is:
- โ **Expected** to be in client-side code
- โ **Safe** when RLS (Row Level Security) is properly configured
- โ ๏ธ **Risky** if RLS is missing or misconfigured
- โ **Not the same** as the service_role key (which should NEVER be in client code)
### Key Format
Supabase anon keys are JWTs:
```
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImFiYzEyMyIsInJvbGUiOiJhbm9uIiwiaWF0IjoxNjQwMDAwMDAwLCJleHAiOjE5NTUzNjAwMDB9.xxxx
```
Key characteristics:
- Starts with `eyJ` (base64 encoded `{"alg":`)
- Contains `"role":"anon"` in payload
- Project reference in `"ref"` claim
## Extraction Patterns
The skill searches for:
### 1. Direct Key Assignment
```javascript
const SUPABASE_KEY = 'eyJhbGci...'
const SUPABASE_ANON_KEY = 'eyJhbGci...'
```
### 2. Client Initialization
```javascript
createClient(url, 'eyJhbGci...')
createClient(url, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY)
```
### 3. Environment Variable Patterns
```javascript
NEXT_PUBLIC_SUPABASE_ANON_KEY
VITE_SUPABASE_ANON_KEY
REACT_APP_SUPABASE_KEY
SUPABASE_KEY
```
## Usage
### Basic Extraction
```
Extract Supabase anon key from https://myapp.example.com
```
### If URL Already Known
```
Extract anon key for project abc123def
```
## Output Format
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ANON KEY EXTRACTED
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Key Type: anon (public)
Severity: โน๏ธ Expected (verify RLS configuration)
Key: [REDACTED]
dXBhYmFzZSIsInJlZiI6ImFiYzEyM2RlZiIsInJvbGUiOiJhbm
9uIiwiaWF0IjoxNjQwMDAwMDAwLCJleHAiOjE5NTUzNjAwMDB9
.xxxxxxxxxxxxx
Decoded Payload:
โโโ iss: supabase
โโโ ref: abc123def
โโโ role: anon
โโโ iat: 2021-12-20T00:00:00Z
โโโ exp: 2031-12-20T00:00:00Z
Found in:
โโโ /static/js/main.js (line 1253)
createClient('https://abc123def.supabase.co', 'eyJhbGci...')
Next Steps:
โโโ Run supabase-audit-rls to test if RLS protects your data
โโโ Run supabase-audit-tables-read to see what's accessible
โโโ Run supabase-extract-service-key to check for critical leaks
Context updated: .sb-pentest-context.json
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
## Key Validation
The skill validates the extracted key:
```
Validation:
โโโ Format: โ Valid JWT structure
โโโ Decode: โ Payload readable
โโโ Role: โ Confirmed "anon" role
โโโ Project: โ Matches extracted URL (abc123def)
โโโ Expiry: โ Not expired (expires 2031-12-20)
```
## Multiple Keys
If multiple keys are found:
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
MULTIPLE KEYS FOUND
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๏ธ 2 potential Supabase keys detected
1. Anon Key (confirmed)
โโโ Role: anon, Project: abc123def
2. Unknown Key
โโโ Role: service_role โ ๏ธ SEE supabase-extract-service-key
This may be a CRITICAL security issue!
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
## Context Output
Saved to `.sb-pentest-context.json`:
```json
{
"supabase": {
"anon_key": "eyJhbGci...",
"anon_key_decoded": {
"iss": "supabase",
"ref": "abc123def",
"role": "anon",
"iat": 1640000000,
"exp": 1955360000
},
"anon_key_sources": [
{
"file": "/static/js/main.js",
"line": 1253
}
]
}
}
```
## Security Assessment
| Finding | Severity | Description |
|---------|----------|-------------|
| Anon key in client | โน๏ธ Info | Expected, but test RLS |
| Anon key expired | โ ๏ธ P2 | Key should be rotated |
| Multiple anon keys | โ ๏ธ P2 | May indicate key rotation issues |
| Role is not "anon" | ๐ด P0 | Wrong key type exposed! |
## Common Issues
โ **Problem:** Key found but won't decode
โ **Solution:** May be obfuscated or split. Try:
```
Extract anon key with deobfuscation from https://myapp.example.com
```
โ **Problem:** Key doesn't match URL project
โ **Solution:** App may use multiple Supabase projects. Both keys are recorded.
โ **Problem:** No key found but Supabase detected
โ **Solution:** Key may be fetched at runtime. Check network requests:
```
Monitor network for anon key on https://myapp.example.com
```
## Best Practices Reminder
For developers reading this report:
1. **Anon key in client is normal** โ It's designed for this
2. **RLS is critical** โ The anon key relies on RLS for security
3. **Never use service_role in client** โ Use Edge Functions instead
4. **Rotate keys periodically** โ Available in Supabase Dashboard
## MANDATORY: Progressive Context File Updates
โ ๏ธ **This skill MUST update tracking files PROGRESSIVELY during execution, NOT just at the end.**
### Critical Rule: Write As You Go
**DO NOT** batch all writes at the end. Instead:
1. **Before starting any action** โ Log the action to `.sb-pentest-audit.log`
2. **After each discovery** โ Immediately update `.sb-pentest-context.json`
3. **After each significant step** โ Log completion to `.sb-pentest-audit.log`
This ensures that if the skill is interrupted, crashes, or times out, all findings up to that point are preserved.
### Required Actions (Progressive)
1. **Update `.sb-pentest-context.json`** with extracted data:
```json
{
"supabase": {
"anon_key": "eyJhbGci...",
"anon_key_decoded": { ... },
"anon_key_sources": [ ... ]
}
}
```
2. **Log to `.sb-pentest-audit.log`**:
```
[TIMESTAMP] [supabase-extract-anon-key] [START] Beginning anon key extraction
[TIMESTAMP] [supabase-extract-anon-key] [SUCCESS] Anon key extracted
[TIMESTAMP] [supabase-extract-anon-key] [CONTEXT_UPDATED] .sb-pentest-context.json updated
```
3. **If files don't exist**, create them before writing.
**FAILURE TO UPDATE CONTEXT FILES IS NOT ACCEPTABLE.**
## MANDATORY: Evidence Collection
๐ **Evidence Directory:** `.sb-pentest-evidence/02-extraction/`
### Evidence Files to Create
| File | Content |
|------|---------|
| `extracted-anon-key.json` | Anon key with decoded JWT payload |
### Evidence Format
```json
{
"evidence_id": "EXT-ANON-001",
"timestamp": "2025-01-31T10:07:00Z",
"category": "extraction",
"type": "anon_key",
"severity": "info",
"key_data": {
"key_prefix": "eyJhbGciOiJIUzI1NiI...",
"key_suffix": "...xxxx",
"full_key_length": 256
},
"decoded_payload": {
"iss": "supabase",
"ref": "abc123def",
"role": "anon",
"iat": "2021-12-20T00:00:00Z",
"exp": "2031-12-20T00:00:00Z"
},
"source": {
"file": "/static/js/main.js",
"line": 1253,
"context": "createClient('https://abc123def.supabase.co', 'eyJhbGci...')"
},
"validation": {
"format_valid": true,
"role_confirmed": "anon",
"project_matches": true,
"expired": false
}
}
```
## Related Skills
- `supabase-extract-url` โ Get URL first (auto-invoked if needed)
- `supabase-extract-service-key` โ Check for critical service key leak
- `supabase-audit-rls` โ Test if RLS protects your data
- `supabase-audit-tables-read` โ See what data is accessible with this key