How Plane Handles Authentication and Authorization: Django Sessions, CSRF Protection, and RBAC
Plane implements a session-based authentication system using Django's cookie-based sessions and CSRF tokens, paired with centralized service classes in the frontend, while enforcing fine-grained role-based access control through workspace membership validation.
Plane's open-source project management platform employs a dual-layer security architecture that combines Django's proven backend session management with a TypeScript-based service layer in React. This article analyzes the makeplane/plane repository to explain how the system authenticates users via cookies and magic links, integrates OAuth providers, and authorizes actions through workspace-specific permission checks.
Backend Authentication: Django Sessions and CSRF Protection
The backend authentication layer relies on Django's native session framework supplemented with custom middleware for API-specific handling.
API Authentication Middleware
At the core of Plane's request authentication is the APIAuthenticationMiddleware located in apps/api/plane/app/middleware/api_authentication.py. This middleware extracts the Django session from incoming requests and validates CSRF tokens when required, populating request.user for downstream consumers. The middleware ensures that every protected API endpoint receives an authenticated user object or rejects the request with appropriate error handling.
# apps/api/plane/app/middleware/api_authentication.py
class APIAuthenticationMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Django session is automatically attached to request.user
# CSRF validation happens in the view when needed
response = self.get_response(request)
return response
CSRF Token Handling
Plane requires CSRF tokens for state-changing operations (POST, PUT, DELETE). The frontend retrieves these tokens via a dedicated endpoint, and subsequent requests include the token in the X-CSRFTOKEN header. The middleware validates these tokens against the user's session to prevent cross-site request forgery attacks.
Frontend Authentication Service
The frontend abstracts all authentication operations into a centralized service class, promoting consistency across the React application.
The AuthService Class
Located in packages/services/src/auth/auth.service.ts, the AuthService class encapsulates HTTP interactions with the backend. Key methods include:
requestCSRFToken()– Retrieves a fresh CSRF token from/auth/get-csrf-token/generateUniqueCode()– Initiates magic-link authentication via/auth/magic-generate/signOut(baseUrl)– Submits a hidden form containing the CSRF token to/auth/sign-out/
import { AuthService } from "@plane/services";
const auth = new AuthService();
// Retrieve CSRF token (required for POST/PUT/DELETE)
async function getCsrf() {
const { csrf_token } = await auth.requestCSRFToken();
return csrf_token;
}
// Sign-out creates a hidden form with the token and submits it
async function signOut() {
const baseUrl = window.location.origin;
await auth.signOut(baseUrl);
}
Magic-Link Authentication Flow
For passwordless login, Plane generates short-lived unique codes through the generateUniqueCode method. The backend sends an email containing a link (e.g., https://app.plane.so/auth/magic-login/?code=XYZ123), which establishes the session when clicked.
// Request a magic link for a user's email
await auth.generateUniqueCode({ email: "user@example.com" });
OAuth and Single Sign-On (SSO) Integration
Plane supports third-party authentication providers through a modular adapter pattern.
OAuth Adapter Implementation
The apps/api/plane/authentication/adapter/oauth.py file contains the OAuth adapter that exchanges authorization codes from providers (Google, GitHub, etc.) for Plane session tokens. This adapter normalizes provider-specific responses into Plane's user model, creating or updating user records while maintaining the same session-based authentication flow as native logins.
Authorization and Role-Based Access Control (RBAC)
After authentication, Plane enforces fine-grained permissions through workspace and project membership validation.
Workspace Membership Validation
The apps/api/plane/authentication/utils/user_auth_workflow.py module contains utility functions like require_active_member that validate a user's role within specific workspaces. These functions query the WorkspaceMember model and raise PermissionDenied exceptions if the user lacks the required membership status or role level.
# apps/api/plane/authentication/utils/user_auth_workflow.py
def require_active_member(user, workspace_id):
membership = WorkspaceMember.objects.filter(user=user, workspace_id=workspace_id).first()
if not membership or not membership.is_active:
raise PermissionDenied("User is not an active workspace member")
Permission Classes and View Protection
Django REST Framework viewsets utilize custom permission classes that invoke the workflow utilities. These classes verify whether the authenticated user possesses the necessary permissions (admin, member, or viewer) before allowing resource creation, modification, or deletion operations.
Enterprise Edition Enhancements
The packages/types/src/instance/auth-ee.ts file defines extended authentication types for the Enterprise Edition, including fields like is_email_verified and is_super_admin. These additional attributes enable premium features such as mandatory email verification and instance-wide administrative privileges.
End-to-End Authentication Flow
The complete authentication lifecycle involves coordination between the frontend service layer and backend middleware:
- Initial Request – The user initiates login via magic link (
generateUniqueCode) or OAuth callback - Session Establishment – The backend creates a Django session, sets the session cookie, and returns a CSRF token
- Authenticated Requests – The frontend includes the CSRF token in the
X-CSRFTOKENheader for state-changing operations, while the browser automatically sends the session cookie - Authorization Check – Protected views invoke
user_auth_workflowutilities to validate workspace membership before processing requests
Summary
- Plane utilizes Django session cookies with CSRF token validation to maintain secure, stateful authentication connections between clients and the API
- The AuthService class in
packages/services/src/auth/auth.service.tscentralizes all frontend authentication logic, including token retrieval and magic-link generation - OAuth integration adapts third-party identity providers to Plane's native session system through the adapter pattern in
apps/api/plane/authentication/adapter/oauth.py - Role-based access control is enforced through workspace membership checks in
apps/api/plane/authentication/utils/user_auth_workflow.py, which validates user roles before resource access - Enterprise Edition extends the authentication model with additional verification fields and administrative capabilities via
packages/types/src/instance/auth-ee.ts
Frequently Asked Questions
What authentication methods does Plane support?
Plane supports email-based magic links, traditional email/password combinations, and OAuth 2.0 providers including Google and GitHub. The OAuth implementation adapts external provider responses to Plane's internal session system, ensuring consistent authentication semantics regardless of the login method used.
How does Plane protect against CSRF attacks?
Plane implements double-submit cookie pattern validation through the APIAuthenticationMiddleware. The frontend retrieves a CSRF token via AuthService.requestCSRFToken() and submits it in the X-CSRFTOKEN header for all state-changing requests. The backend validates this token against the user's session before processing the request, preventing unauthorized cross-site commands.
How is workspace access authorization enforced?
Authorization relies on the user_auth_workflow.py utilities, which query the WorkspaceMember model to verify active membership and role levels (admin, member, viewer). Django REST Framework permission classes invoke these utilities, returning 403 Forbidden responses when users attempt actions outside their permission scope within specific workspaces or projects.
Can Plane integrate with corporate identity providers?
Yes, through the OAuth adapter (apps/api/plane/authentication/adapter/oauth.py), Plane can integrate with any OAuth 2.0-compliant identity provider. The adapter exchanges the provider's authorization code for a Plane session, creating or updating user records while maintaining the same workspace-based authorization checks used for native authentication.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →