KeyHippo extends Supabase's Row Level Security (RLS) framework, enabling seamless integration of API key authentication within existing security policies.
KeyHippo addresses the challenge of incorporating API key authentication in Supabase applications without compromising the integrity of Row Level Security. It achieves this by extending the RLS framework to encompass both session-based and API key authentication methods within a unified security context. This approach eliminates the need for parallel security structures and maintains granular access control across authentication types.
Top features:
- Unified RLS policies supporting dual authentication methods
- SQL-based API key issuance
- Preservation of existing Supabase RLS implementations
- Essential API key lifecycle management
-
Install the KeyHippo extension:
select dbdev.install('keyhippo@keyhippo'); create extension "keyhippo@keyhippo" version '0.0.40';
Consult database.dev for version updates.
-
Post-installation, KeyHippo functions become accessible within your database environment.
For more detailed information on the PostgreSQL extension, see the extension readme.
Install via npm:
npm install keyhippo
For more information on the npm package, including usage examples, see the client readme.
import { KeyHippo } from "keyhippo";
const keyHippo = new KeyHippo(supabaseClient);
const result = await keyHippo.createApiKey(userId, "Primary API Key");
Example of a policy supporting dual authentication:
CREATE POLICY "owner_access"
ON "public"."resource_table"
USING (
auth.uid() = resource_table.owner_id
OR auth.keyhippo_check(resource_table.owner_id)
);
This policy grants access when the user is authenticated via a session token (auth.uid()
) or a valid API key associated with the resource owner (auth.keyhippo_check()
).
revokeApiKey
: Invalidate an existing API keyloadApiKeyInfo
: Retrieve metadata for existing keysgetAllKeyMetadata
: Comprehensive metadata for a user's API keys
For more detailed usage instructions and API reference, please see the documentation.
KeyHippo ensures that API keys are never stored in any form and cannot be reconstructed, even with access to the database.
sequenceDiagram
title: API Key Creation Process
autonumber
participant B as Browser
participant S as Server
participant A as Auth Service
participant K as KeyHippo (Postgres)
participant V as Supabase Vault
B->>S: Initial request (e.g., page load)
S->>S: Initialize Supabase client (URL, anonKey)
S->>A: signInAnonymously() or signInWithProvider()
A-->>S: Return Session (user.id, session.accessToken)
B->>S: Request API key creation
S->>S: Initialize KeyHippo instance
S->>K: createApiKey(userId, keyDescription)
K->>K: Verify auth.uid() matches userId
K->>K: Generate UUID (jti) using gen_random_uuid()
K->>K: Generate current timestamp and expiry (100 years from now)
K->>K: Construct JWT body (role, aud, iss, sub, iat, exp, jti)
K->>V: Retrieve user_api_key_secret for userId
K->>V: Retrieve project_api_key_secret
K->>V: Retrieve project_jwt_secret
K->>K: Sign JWT with project_jwt_secret
K->>K: Generate api_key = HMAC(jwt, user_api_key_secret, sha512)
K->>K: Generate project_hash = HMAC(api_key, project_api_key_secret, sha512)
K->>V: Store in vault.secrets: (secret: jwt, name: project_hash, description: keyDescription)
K->>V: Store in auth.jwts: (secret_id: UUID of stored secret, user_id: userId)
K-->>S: Return api_key (derived, not stored)
S-->>B: Return API key to client
This design offers several key security benefits:
- Unique Key Generation: Each invocation of
keyhippo.create_api_key
produces a distinct key, regardless of input consistency. - Temporal Uniqueness: The use of high-precision timestamps ensures that keys created in rapid succession remain unique.
- Cryptographic Irreversibility: The multi-stage hashing process renders the key generation process cryptographically irreversible.
- Breach Resilience: In the event of a database compromise, the stored hashes provide no mechanism to regenerate or deduce the original API keys.
- Separation of Concerns: The utilization of Supabase Vault for secret management adds an additional layer of security.
This diagram illustrates the sequence of operations that occur when an API request is made using a KeyHippo-generated API key:
sequenceDiagram
title: Authenticated API Request
autonumber
participant C as API Client
participant S as Server
participant K as KeyHippo (Postgres)
participant P as Postgres RLS
participant V as Supabase Vault
C->>S: API request with API key in header
S->>S: Extract API key from Authorization header
S->>K: RPC: get_uid_for_key(user_api_key: apiKey)
K->>V: Retrieve project_api_key_secret
V-->>K: Return project_api_key_secret
K->>K: Hash API key with project_api_key_secret
K->>P: Look up hashed API key in vault.secrets
P-->>K: Return matching secret_uuid if found
K->>P: Query auth.jwts for user_id using secret_uuid
P-->>K: Return user_id
K-->>S: Return user_id
alt user_id found
S->>S: Supabase client authenticated with user_id
S->>P: Execute query (including API key in header and user_id)
P->>P: Evaluate RLS policy: (auth.uid() = owner_id) OR (keyhippo.key_uid() = owner_id)
P->>K: Call keyhippo.key_uid()
K->>K: Extract API key from request.headers
K->>V: Retrieve project_api_key_secret
V-->>K: Return project_api_key_secret
K->>K: Hash API key with project_api_key_secret
K->>P: Look up hashed API key in vault.secrets
P-->>K: Return matching secret_uuid if found
K->>P: Query auth.jwts for user_id using secret_uuid
P-->>K: Return user_id
K-->>P: Return user_id for RLS evaluation
P->>P: Complete RLS policy evaluation
P-->>S: Return RLS-filtered query results
S-->>C: Return API response with data
else user_id not found
S-->>C: Return authentication error
end
Note the seamless integration of KeyHippo's authentication process with Supabase's existing RLS framework. This approach ensures that API key authentication adheres to the same security policies as session-based authentication, maintaining a consistent security model across different authentication methods.
For more detailed architectural information, please see the Architecture documentation.
KeyHippo is currently in alpha status. We adhere to semantic versioning, and as such, KeyHippo will remain in alpha (versions < 0.1.0) until we've thoroughly validated its stability and feature completeness in production environments. During this phase, we welcome early adopters to provide feedback and report issues.
KeyHippo emerged from a pattern observed across Integrated Reasoning's Supabase projects: the need to reconcile API key authentication with Row Level Security policies. This challenge, also noted in Supabase's GitHub discussions (#4419), highlighted a gap in existing solutions.
We developed KeyHippo to address this, drawing insights from community discussions and approaches. The result is a streamlined, production-ready system for API key management in Supabase applications.
KeyHippo welcomes community contributions. For guidance on contributing, please refer to our Contributing Guide.
KeyHippo is distributed under the MIT license. See the LICENSE file for details.
For technical issues, feature requests, or general inquiries, please open an issue on our GitHub repository.
For commercial support options, consult keyhippo.com.