Multi-tenancy with tenant tokens
Tenant tokens are short-lived, scoped credentials generated from an API key. They embed search rules (filters) that automatically apply to every search request, ensuring users only see their own data.| Concept | Purpose |
|---|---|
| API keys | Authenticate API requests, define base permissions |
| Tenant tokens | Restrict search results per user with embedded filters |
| Search rules | Filter expressions baked into a token (e.g., user_id = 123) |
When to use tenant tokens
Use tenant tokens when multiple users or organizations share the same Meilisearch index but should only see their own data. Common examples include SaaS platforms, marketplace search, and personalized content feeds. If you are familiar with other search or database systems, tenant tokens serve a similar purpose to Algolia’s secured API keys or PostgreSQL’s row-level security (RLS). They let you restrict search results per user without creating separate indexes for each tenant.Tenant tokens only restrict the search endpoint. They do not apply to admin operations such as indexing, settings updates, or API key management. Use API keys to control access to those endpoints.
Security model
Meilisearch uses a layered key hierarchy to manage access:| Level | Key type | Purpose |
|---|---|---|
| 1 | Admin API key | Allows creating and managing indexes, settings, and other API keys. Used by your backend. |
| 2 | Search API key | Permits only search operations. Safe to use in frontend applications when data is not multi-tenant. |
| 3 | Tenant token | Generated in your backend from an API key. Embeds search rules (filters) that automatically restrict results per user. Short-lived and scoped. |
How it works
- Meilisearch provides a default admin API key and search API key.
- Your backend uses the admin key to manage indexes and settings.
- When a user authenticates in your application, your backend generates a tenant token from the search key, embedding user-specific filter rules (for example,
tenant_id = 42). - The frontend uses this tenant token to query Meilisearch directly. Every search automatically applies the embedded filters, so users never see data belonging to other tenants.
Sanitizing search results
Meilisearch indexes and returns document content as-is. If your documents contain user-generated content, you must sanitize or escape all field values before rendering them in HTML. Failing to do so can expose your application to cross-site scripting (XSS) attacks. For example, if a document’stitle field contains <script>alert('xss')</script> and your frontend renders it with innerHTML or similar unescaped output, the script will execute in your users’ browsers.
To prevent this:
- Always escape or sanitize document field values before inserting them into the DOM
- Use your framework’s built-in escaping (React, Vue, and Angular escape by default when using standard template syntax)
- Be especially careful with
dangerouslySetInnerHTML(React),v-html(Vue), or any other raw HTML rendering method - Consider using a sanitization library such as DOMPurify if you need to render rich HTML content from search results
Next steps
Getting started
Generate your first tenant token using an SDK
Token from scratch
Build a tenant token manually without an SDK
Token payload
Reference for tenant token JWT payload structure
Manage API keys
Create, rotate, and scope API keys