KeyHippo simplifies the creation of unified RLS policies that handle both session-based and API key authentication methods.

Understanding Unified Policies

Unified RLS policies in KeyHippo allow you to define access rules that work consistently across different authentication methods. This approach ensures that your security policies are comprehensive and easy to maintain.

Key Components:

  1. auth.uid(): Supabase’s built-in function for session-based authentication.
  2. auth.keyhippo_check(): KeyHippo’s function for API key authentication.

Basic Unified Policy

Here’s a simple example of a unified RLS policy:

CREATE POLICY "owner_access"
ON "public"."resources"
USING (
  auth.uid() = resources.owner_id
  OR auth.keyhippo_check(resources.owner_id)
);

This policy grants access if:

  • The user is authenticated via a session and their ID matches the owner_id, OR
  • The request includes a valid API key associated with the owner_id.

Advanced Policy Patterns

Role-Based Access Control (RBAC)

Combine KeyHippo with role checks for more granular control:

CREATE POLICY "admin_access"
ON "public"."sensitive_data"
USING (
  (auth.uid() IN (SELECT user_id FROM user_roles WHERE role = 'admin'))
  OR (auth.keyhippo_check(auth.uid()) AND
      auth.uid() IN (SELECT user_id FROM user_roles WHERE role = 'admin'))
);

This policy allows access only if the user (authenticated via session or API key) has an ‘admin’ role.

Multi-Tenant Policies

For multi-tenant applications:

CREATE POLICY "tenant_data_access"
ON "public"."tenant_data"
USING (
  (auth.uid() = tenant_data.user_id AND tenant_data.tenant_id = current_setting('app.current_tenant')::uuid)
  OR (auth.keyhippo_check(tenant_data.user_id) AND tenant_data.tenant_id = current_setting('app.current_tenant')::uuid)
);

This policy ensures that users can only access data for their specific tenant, regardless of authentication method.

Leveraging KeyHippo-Specific Functions

KeyHippo provides additional functions to enhance your RLS policies:

keyhippo.key_uid()

Retrieves the user ID associated with the current API key:

CREATE POLICY "api_key_specific_access"
ON "public"("api_resources")
USING (
  auth.uid() IS NOT NULL
  OR (keyhippo.key_uid() IS NOT NULL AND api_resources.allowed_key_id = keyhippo.key_uid())
);

This policy allows access if the user is authenticated or if the API key used is specifically allowed for the resource.

keyhippo.get_api_key_metadata()

Fetches metadata about API keys, useful for policies based on key properties:

CREATE POLICY "premium_api_access"
ON "public"."premium_resources"
USING (
  auth.uid() IS NOT NULL
  OR (
    keyhippo.key_uid() IS NOT NULL
    AND EXISTS (
      SELECT 1
      FROM keyhippo.get_api_key_metadata(keyhippo.key_uid()) AS key_meta
      WHERE key_meta.permission = 'premium'
    )
  )
);

This policy grants access to premium resources only if the API key has ‘premium’ permission.

Best Practices for Unified Policies

  1. Consistency: Ensure that your policies treat session-based and API key authentication consistently where appropriate.

  2. Granularity: Create separate policies for different operations (SELECT, INSERT, UPDATE, DELETE) rather than using catch-all policies.

  3. Performance: Be mindful of policy complexity. Overly complex policies can impact query performance.

  4. Testing: Thoroughly test your policies with both authentication methods to ensure they behave as expected.

  5. Documentation: Maintain clear documentation of your RLS policies, including the reasoning behind each policy.

Policy Maintenance and Evolution

As your application evolves, so should your RLS policies:

  1. Regular Reviews: Periodically review and update your policies to ensure they align with your current security requirements.

  2. Version Control: Keep your policies in version control to track changes over time.

  3. Audit Logging: Implement logging to track policy evaluations and identify potential issues or optimization opportunities.

Advanced RLS Techniques

Explore more sophisticated RLS policy patterns and techniques.