Bypass Mode¶
Bypass mode allows specific operations to read data across tenant boundaries. This is necessary for authentication, admin dashboards, analytics, and other cross-tenant operations.
Admin Bypass¶
The primary bypass mechanism is the admin flag. When rls.is_admin is set to 'true',
the RLS policy allows access to all rows:
from django_rls_tenants import admin_context
with admin_context():
# All rows visible regardless of tenant
all_users = User.objects.all()
This is used by:
admin_context()context managerRLSTenantMiddlewarewhen the user hasis_tenant_admin=Truerls_bypass()test helper (a convenience wrapper aroundadmin_context)
Extra Bypass Flags¶
For edge cases where you need read-only bypass without full admin access, use
extra_bypass_flags on the RLSConstraint:
from django_rls_tenants.rls import RLSConstraint
from django_rls_tenants import RLSProtectedModel
class ProtectedUser(RLSProtectedModel):
# ...
class Meta(RLSProtectedModel.Meta):
constraints = [
RLSConstraint(
field="tenant",
name="%(app_label)s_%(class)s_rls_constraint",
extra_bypass_flags=["rls.auth_bypass"],
),
]
How Extra Bypass Flags Differ from Admin¶
| Behavior | Admin bypass | Extra bypass flags |
|---|---|---|
Added to USING clause (SELECT/UPDATE/DELETE) |
Yes | Yes |
Added to WITH CHECK clause (INSERT/UPDATE) |
Yes | No |
| Allows reading all rows | Yes | Yes |
| Allows inserting/updating without tenant | Yes | No |
Extra bypass flags are intentionally read-only. This prevents accidental writes without proper tenant context.
Setting Bypass Flags¶
Use the imperative helpers or context manager:
from django_rls_tenants.tenants.bypass import set_bypass_flag, clear_bypass_flag, bypass_flag
# Context manager (recommended):
with bypass_flag("rls.auth_bypass"):
user = User.objects.get(email="admin@example.com")
# Imperative (for middleware-style code):
set_bypass_flag("rls.auth_bypass")
try:
user = User.objects.get(email="admin@example.com")
finally:
clear_bypass_flag("rls.auth_bypass")
Use Case: Authentication¶
During authentication, the user record must be read before the tenant context is known. A bypass flag allows the auth backend to read user records without setting a full admin context:
from django_rls_tenants.tenants.bypass import bypass_flag
class RLSAuthBackend:
def authenticate(self, request, username=None, password=None):
from myapp.models import User
with bypass_flag("rls.auth_bypass"):
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
return None
if user.check_password(password):
return user
return None
Security Implications¶
Warning
Bypass modes weaken tenant isolation. Use them only when necessary and for the narrowest scope possible.
Guidelines:
- Prefer
tenant_contextoveradmin_contextwhen you know the tenant. - Use
extra_bypass_flagsinstead ofadmin_contextwhen you only need read access. - Keep bypass blocks small -- enter and exit as quickly as possible.
- Never expose bypass to end users -- bypass should only be used in server-side code that you control.
- Audit bypass usage -- search your codebase for
admin_context,rls_bypass, andbypass_flagto understand your bypass surface area.
When Bypass Is Needed¶
| Scenario | Recommended approach |
|---|---|
| Authentication backends | extra_bypass_flags with bypass_flag() context manager |
| Admin dashboards | admin_context() or is_tenant_admin=True on the user |
| Cross-tenant analytics | admin_context() |
| Data migrations | admin_context() |
| Management commands | admin_context() or tenant_context() depending on scope |
| Background tasks | tenant_context(tenant_id) when tenant is known |