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 |
|---|---|---|
In CASE WHEN condition (USING clause) |
Yes | Yes |
In CASE WHEN condition (WITH CHECK clause) |
Yes | No |
| Allows reading all rows | Yes | Yes |
| Allows inserting/updating without tenant | Yes | No |
The RLS policy uses a CASE WHEN structure where bypass conditions are checked
first. If any bypass condition is true, the tenant match is skipped entirely.
Extra bypass flags appear only in the USING clause, so they enable read access
(SELECT/UPDATE/DELETE) but not writes without a valid 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 |