> algolia-security-basics

Apply Algolia security best practices: API key scoping, secured API keys, frontend vs backend key separation, and key rotation. Trigger: "algolia security", "algolia API key security", "secure algolia", "algolia secrets", "algolia key rotation", "algolia secured key".

fetch
$curl "https://skillshub.wtf/jeremylongshore/claude-code-plugins-plus-skills/algolia-security-basics?format=md"
SKILL.mdalgolia-security-basics

Algolia Security Basics

Overview

Algolia's security model is built around scoped API keys. Every Algolia app has three default keys (Admin, Search-Only, Monitoring). For production, create custom keys with minimal permissions and use Secured API Keys for per-user/per-tenant restrictions.

Key Types and Where to Use Them

Key TypeACLExpose to Frontend?Use Case
AdminAll operationsNEVERBackend indexing, settings, key management
Search-Onlysearch onlyYes (safe)Frontend search widgets
MonitoringRead monitoring dataNoHealth checks, dashboards
CustomYou define ACLDepends on ACLScoped backend services
SecuredDerived from parent keyYesPer-user filtered search

Instructions

Step 1: Environment Variable Setup

# .env (NEVER commit — add to .gitignore)
ALGOLIA_APP_ID=YourApplicationID
ALGOLIA_ADMIN_KEY=admin_api_key_here        # Backend only
ALGOLIA_SEARCH_KEY=search_only_key_here     # OK for frontend

# .gitignore — MUST include:
.env
.env.local
.env.*.local

Step 2: Create Scoped API Keys

import { algoliasearch } from 'algoliasearch';

const client = algoliasearch(process.env.ALGOLIA_APP_ID!, process.env.ALGOLIA_ADMIN_KEY!);

// Create a write-only key for a specific microservice
const { key: indexingKey } = await client.addApiKey({
  apiKey: {
    acl: ['addObject', 'deleteObject', 'editSettings'],
    description: 'Product sync service — write only',
    indexes: ['products', 'products_staging'],  // Restrict to specific indices
    maxQueriesPerIPPerHour: 5000,
    referers: [],  // Empty = no referer restriction (backend use)
  },
});

// Create a search key restricted to specific referers (frontend)
const { key: frontendKey } = await client.addApiKey({
  apiKey: {
    acl: ['search'],
    description: 'Frontend search — domain-restricted',
    indexes: ['products'],
    referers: ['https://mystore.com/*', 'https://*.mystore.com/*'],
    maxQueriesPerIPPerHour: 1000,
    maxHitsPerQuery: 50,
  },
});

Step 3: Generate Secured API Keys (Per-User Filtering)

// Secured API keys are generated on YOUR server, not via Algolia API.
// They embed restrictions that the client can't bypass.

function generateUserSearchKey(userId: string, tenantId: string): string {
  const client = algoliasearch(process.env.ALGOLIA_APP_ID!, process.env.ALGOLIA_ADMIN_KEY!);

  return client.generateSecuredApiKey({
    parentApiKey: process.env.ALGOLIA_SEARCH_KEY!,
    restrictions: {
      // User can only see their tenant's data
      filters: `tenant_id:${tenantId}`,
      // Key expires in 1 hour
      validUntil: Math.floor(Date.now() / 1000) + 3600,
      // Restrict to specific indices
      restrictIndices: ['products'],
      // Optional: restrict sources (IPs)
      restrictSources: '',
    },
  });
}

// Usage in your API endpoint:
// const userKey = generateUserSearchKey(req.user.id, req.user.tenantId);
// return { appId: process.env.ALGOLIA_APP_ID, searchKey: userKey };

Step 4: Key Rotation Procedure

async function rotateApiKey(oldKeyDescription: string) {
  const client = algoliasearch(process.env.ALGOLIA_APP_ID!, process.env.ALGOLIA_ADMIN_KEY!);

  // 1. List keys to find the old one
  const { keys } = await client.listApiKeys();
  const oldKey = keys.find(k => k.description === oldKeyDescription);
  if (!oldKey) throw new Error(`Key not found: ${oldKeyDescription}`);

  // 2. Create new key with same ACL
  const { key: newKey } = await client.addApiKey({
    apiKey: {
      acl: oldKey.acl,
      description: `${oldKeyDescription} (rotated ${new Date().toISOString().split('T')[0]})`,
      indexes: oldKey.indexes || [],
      maxQueriesPerIPPerHour: oldKey.maxQueriesPerIPPerHour || 0,
      referers: oldKey.referers || [],
    },
  });

  console.log(`New key created: ...${newKey.slice(-8)}`);
  console.log('Update your env vars, then delete the old key:');
  console.log(`  client.deleteApiKey({ key: '${oldKey.value}' })`);

  return newKey;
}

Security Checklist

  • Admin key in env vars, never in frontend code or git
  • .env files in .gitignore
  • Frontend uses Search-Only or Secured API key
  • Custom keys have minimal ACL (least privilege)
  • referers set on frontend keys to prevent abuse
  • maxQueriesPerIPPerHour set on all public keys
  • Secured API keys have validUntil (expiration)
  • Key rotation scheduled quarterly
  • Git history scanned for accidentally committed keys

Error Handling

Security IssueDetectionMitigation
Admin key exposed in frontendCode review, git scanningRotate immediately, restrict referers
Key in git historygit log -S 'ALGOLIA'Rotate key, use git-secrets or gitleaks
Excessive ACL on keyAudit key permissionsCreate scoped replacement key
Expired secured keyvalidUntil in the pastGenerate fresh secured key

Resources

Next Steps

For production deployment, see algolia-prod-checklist.

┌ stats

installs/wk0
░░░░░░░░░░
github stars1.7K
██████████
first seenMar 23, 2026
└────────────

┌ repo

jeremylongshore/claude-code-plugins-plus-skills
by jeremylongshore
└────────────