Skip to content

Organization Authorization Flow

This diagram shows how organization access is selected, enforced, and checked for both UI and API requests.

flowchart TD
    A[User logs in] --> B[PostLoginRedirectView]
    B --> C{default_organization_id set?}
    C -- yes --> D[OrganizationAuthRedirectView for default org]
    C -- no --> E[SetDefaultOrganizationView]
    E --> F[OrganizationAuthRedirectView after user picks org]

    D --> G[Activate organization session]
    F --> G
    G --> H[request.session.active_organization_id]
    G --> I[request.session.organization payload]

    H --> J[OrganizationMiddleware]
    I --> J
    J --> K[request.organization_context]
    J --> L[request.organization]
    J --> M[request.membership]

    K --> N[UI request to organizations org detail path]
    K --> O[API request to org scoped endpoint]

    N --> P[OrganizationScopedMixin]
    O --> Q[HasOrganizationContext]

    P --> R{URL org matches active org?}
    Q --> S{route org matches active org?}

    R -- no --> F
    S -- no --> T[403 Forbidden]

    R -- yes --> U[Check required permission]
    S -- yes --> U

    U --> V[Scope queryset to active organization]
    V --> W[Object belongs to active organization]
    W --> X[Check object belongs to active organization]
    X --> Y[Access granted]

What Enforces What

  • OrganizationAuthRedirectView is the only supported switch point.
  • OrganizationMiddleware resolves the active organization from session state.
  • OrganizationMiddleware also sets request-local org context for manager-level default scoping.
  • OrganizationScopedMixin blocks UI requests when the URL org does not match the active org.
  • HasOrganizationContext blocks API requests when the route org does not match the active org.
  • require_permission() and require_object_in_active_org() enforce role and object-level checks.

Query Safety Notes

  • For models inheriting OrganizationOwnedModel, objects is request-scoped by default.
  • Keep .for_organization(request.organization) in critical paths for defense in depth.
  • Use .unscoped_objects only for intentional cross-organization operations.

Practical Rule

A user can belong to multiple organizations, but they must switch the active organization through the auth flow before reading or mutating data in that org. Changing the URL alone is not enough.