Skip to content

Permissions

The core permission layer defines DRF permission classes used to protect API endpoints.

These permissions ensure that:

  • requests are authenticated
  • a valid organization context is present
  • users have the correct type of access (internal vs customer)

They act as the entry gate before any view or service logic is executed.


Purpose

Permissions answer:

  • Is this request allowed to proceed?
  • Is the user authenticated?
  • Is there a valid organization context?

They operate at the request level, not the business logic level.


Relationship to Policies

Permissions and policies serve different roles:

Permissions (this layer)

  • tied to DRF
  • operate on requests
  • enforce authentication and context
  • run before views

Policies

  • domain-level logic
  • reusable across services
  • independent of HTTP

Available Permission Classes

HasCurrentOrg

Ensures that the request is scoped to a valid internal organization.

Behavior

  • allows access if request.org is already set
  • otherwise attempts to resolve org from headers
  • denies access if:
  • user is not authenticated
  • org cannot be resolved
  • user is not a member of the org

Usage

Apply to all endpoints that operate on internal organization data.


HasCurrentCustomerOrg

Ensures that the request is scoped to a valid customer organization.

Behavior

  • resolves request.customer_org from header:
  • X-CUSTOMER-ORG-ID
  • validates:
  • org exists and is active
  • org is of type customer
  • user has membership (unless superuser)

Usage

Apply to customer-facing endpoints.


IsInternalUser

Ensures that the user has at least one active internal org membership.

Behavior

  • requires authentication
  • checks:
  • user has at least one active OrgMembership

Usage

Useful for: - general internal access endpoints - dashboards or shared resources


IsCustomerUser

Ensures that the user has at least one active customer org membership.

Behavior

  • requires authentication
  • checks:
  • user has at least one active CustomerMembership

Usage

Useful for: - customer portal access - external-facing features


Permission Flow

flowchart TD
    A[Incoming Request] --> B[Permission Check]
    B --> C{Authenticated?}
    C -->|No| D[Reject]
    C -->|Yes| E[Resolve Org]
    E --> F{Valid Context?}
    F -->|No| D
    F -->|Yes| G[Allow Access]

Usage in Views

Permissions are applied at the view level.

Example:

permission_classes = [IsAuthenticated, HasCurrentOrg]

This ensures: - user is authenticated - request.org is valid and attached


Execution Order

Permissions run before: - serializer validation - view logic - service calls

If a permission fails: - the request is rejected immediately - no business logic is executed


Error Behavior

If a permission fails: - response status is typically 403 Forbidden - message explains the failure reason

Example:

{ "detail": "X-ORG-SLUG or X-ORG-ID required (and you must be a member)." }


Best Practices

Always use HasCurrentOrg

For any endpoint that interacts with internal org data.


Keep views clean

Do not: - manually resolve org in views - perform membership checks in views


Combine permissions when needed

Example:

permission_classes = [ IsAuthenticated, HasCurrentOrg, ]


Use policies for deeper checks

Permissions should not replace policies.

Example: - permission -> ensures request is valid - policy -> ensures user can perform specific action


Common Mistakes

Missing HasCurrentOrg

Leads to: - missing request.org - potential data leaks


Duplicating permission logic in views

Avoid: - manual membership checks - inline role checks


Using permissions for business rules

Permissions should NOT: - enforce workflow constraints - validate domain state - replace service logic


Example Flow

  1. Request hits endpoint
  2. DRF evaluates permissions
  3. HasCurrentOrg resolves org
  4. request.org is attached
  5. View executes
  6. Service performs business logic

Summary

The permission layer ensures that: - every request is authenticated - every request has a valid org context - invalid requests are rejected early

It is the first line of defense in the backend architecture.