Security Considerations¶
django_tomselect is designed to integrate seamlessly with Django’s authentication and authorization frameworks. It provides built-in mechanisms for controlling data visibility, validating permissions, and restricting access to autocomplete endpoints. By configuring permissions, employing authorization hooks, and leveraging caching, you can ensure that your autocomplete fields expose only allowed data to authorized users.
Visualizing Security¶
stateDiagram-v2
[*] --> CheckAuth: Request received
CheckAuth --> SkipAuth: skip_authorization=True
CheckAuth --> AllowAnon: allow_anonymous=True
CheckAuth --> ValidateUser: Regular auth flow
SkipAuth --> ProcessRequest: Allow
AllowAnon --> ProcessRequest: Allow
ValidateUser --> CheckCache: User authenticated
ValidateUser --> RejectRequest: User not authenticated
CheckCache --> UseCache: Cache hit
CheckCache --> CheckPerms: Cache miss
CheckPerms --> CachePerms: Has permission
CheckPerms --> RejectRequest: No permission
CachePerms --> ProcessRequest
UseCache --> ProcessRequest
ProcessRequest --> [*]: Complete
RejectRequest --> [*]: Reject
Permission Handling¶
Security often begins with permission checks. django_tomselect supports permission-based restrictions on Model-type autocomplete views, allowing you to define who can see, search, or create new entries. Iterables-type components, on the other hand, do not benefit from built-in permission checks and rely on your custom logic.
Model-type vs. Iterables-type Components¶
Model-type Components: When using
AutocompleteModelView, permissions are integrated. You can rely on the model’s defined permissions (e.g.,view,add,change,delete) to restrict access. Note that built-in view-permission enforcement is opt-in: it only applies when you setpermission_requiredon the view (or overridehas_permission). By defaultpermission_required = None, in which casehas_permissionreturnsTruefor any authenticated user, so a user without theviewpermission will still see the model instances. Setpermission_required = "app_label.view_modelname"to require theviewpermission.Iterables-type Components: For iterables-based autocomplete (
AutocompleteIterablesView), there are no out-of-the-box permission checks. You must implement your own filtering or conditional logic in the view to ensure only allowed data is returned.
Request Passing for Authentication¶
django_tomselect automatically receives the request object through its views, making it possible to check request.user and confirm that the user is authenticated and authorized before returning data. Ensure that your URLs or views are protected by login_required, LoginRequiredMixin, or custom permission checks so that the request.user is set and reliable.
Class Variable Priority and Usage¶
AutocompleteModelView provides several class-level attributes that let you fine-tune authorization logic. These attributes influence how permissions are enforced and in which order:
permission_required: Specifies exact permissions needed. This could be a single permission string or a list of permissions required to access the data.allow_anonymous: If set toTrue, anonymous users are allowed access, bypassing normal permission checks. Use with caution.skip_authorization: Setting this toTruedisables all permission checks entirely, allowing unrestricted access to the autocomplete. Use only in trusted or controlled environments.
Priority:
skip_authorization (highest)
allow_anonymous
permission_required (lowest)
If skip_authorization is True, no checks are performed at all. If it’s False, but allow_anonymous is True, then no authentication is required. Otherwise, permission_required is evaluated against request.user.
Object-level Permissions¶
Override has_object_permission() to evaluate access for a single resolved object:
class ArticleAutocompleteView(AutocompleteModelView):
model = Article
def has_object_permission(self, request, obj, action="view"):
# Restrict visibility to objects owned by the current user
return obj.owner == request.user
Important
has_object_permission() runs when the view resolves specific objects by ID - for example when a CompositeAutocompleteView (token search) turns previously-selected IDs back into labels. It is not called for every row of the autocomplete suggestion listing. To restrict which objects appear in the dropdown as the user types (e.g. “user A can see only articles they own, while user B can see all”), filter the queryset instead.
class ArticleAutocompleteView(AutocompleteModelView):
model = Article
def get_queryset(self):
# Only the current user's own articles appear in the dropdown
return super().get_queryset().filter(owner=self.request.user)
Combine object-level checks with Django’s permission system or third-party packages like django-guardian to implement fine-grained access control.
Custom and Third-party Auth Systems¶
For more complex scenarios (e.g., OAuth, SSO, or custom backends), subclass AutocompleteModelView and integrate with your custom authentication logic. Implement checks in has_permission() or has_object_permission() to validate tokens, interact with external services, or apply custom roles and policies.
django_tomselect does not impose any specific authentication mechanism, allowing you to seamlessly integrate solutions like django-guardian for per-object permissions or adapt to enterprise SSO systems.
User Permission Caching and Invalidation¶
Checking permissions repeatedly can be costly. django_tomselect provides an optional permission caching mechanism to speed up subsequent checks. When enabled, permissions are cached per user, model, and action, so changes in user roles or memberships require invalidating the cache (via AutocompleteModelView.invalidate_permissions(user=...) or the module-level permission_cache) to take effect immediately.
For configuration, behavior, cache-backend support, and the full invalidation API, see Permission Caching.
Content Security Policy (CSP) Nonce Support¶
If your application uses a Content Security Policy to restrict inline scripts, django-tomselect supports CSP nonces. This allows you to avoid setting 'unsafe-inline' in your script-src directive.
How It Works¶
When a CSP nonce is available on the request object, django-tomselect automatically adds it to the inline <script> tags it renders:
<script nonce="abc123...">
// TomSelect initialization code
</script>
Setup with django-csp¶
If you use django-csp, the nonce is available automatically. Ensure the django-csp middleware is installed and configured:
# settings.py
MIDDLEWARE = [
# ...
"csp.middleware.CSPMiddleware",
"django_tomselect.middleware.TomSelectMiddleware",
# ...
]
CONTENT_SECURITY_POLICY = {
"DIRECTIVES": {
"script-src": ["'self'", "'nonce'"], # django-csp will replace 'nonce' with the actual nonce
},
}
No additional configuration in django-tomselect is needed - the widget reads the nonce from request.csp_nonce (or request._csp_nonce) and passes it to the template context automatically.
Custom CSP Middleware¶
If you use a custom CSP middleware, ensure it sets request.csp_nonce or request._csp_nonce to the nonce value. django-tomselect will detect and use it.
Without CSP¶
If no CSP nonce is present on the request, the <script> tags render without a nonce attribute, maintaining full backward compatibility.