Security Configurations and Authentication Mechanisms in Plane: A Complete Technical Guide

Plane employs a multi-layered security architecture combining API key authentication, Django session management with CSRF tokens, secret-key middleware for internal services, and JWT-signed invitations to protect project management resources.

Plane is an open-source project management platform that implements defense-in-depth through distinct authentication layers for different access patterns. Understanding these security configurations and authentication mechanisms is essential for developers integrating with the REST API, securing self-hosted deployments, or extending the frontend. The codebase separates concerns between programmatic API access, browser-based user sessions, and inter-service communication.

API Key Authentication

For programmatic access to the REST API, Plane uses a custom APIKeyAuthentication class located in apps/api/plane/app/middleware/api_authentication.py. This middleware reads the X-Api-Key header and verifies the token against the APIToken model in the database.

Upon successful validation, the system updates the token's last_used timestamp to track activity. The authentication scheme is automatically documented in the OpenAPI specification through APIKeyAuthenticationExtension in apps/api/plane/utils/openapi/auth.py.

import { APIService } from "@plane/services/api.service";

const api = new APIService(); // base URL is API_BASE_URL
await api.get("/issues/", {
  headers: { "X-Api-Key": "YOUR_API_KEY_HERE" },
});

Session Authentication and CSRF Protection

The web UI relies on Django's session-based authentication extended through BaseSessionAuthentication in apps/api/plane/authentication/session.py. This class extends DRF's standard SessionAuthentication but disables CSRF enforcement for API calls, as the frontend handles CSRF protection separately.

For state-changing operations like password resets or sign-outs, the frontend obtains a fresh CSRF token from the /auth/get-csrf-token/ endpoint through AuthService.requestCSRFToken() in packages/services/src/auth/auth.service.ts. Subsequent POST requests include this token in the X-CSRFTOKEN header to prevent cross-site request forgery.

import { AuthService } from "@plane/services/auth.service";

const auth = new AuthService();
const { csrf_token } = await auth.requestCSRFToken();

await auth.post("/auth/set-password/", { password: "newPass" }, {
  headers: { "X-CSRFTOKEN": csrf_token },
});

Live Server Secret Key Middleware

Internal "live-server" endpoints—such as webhook receivers—utilize shared secret authentication implemented in apps/live/src/lib/auth-middleware.ts. The requireSecretKey Express middleware validates the live-server-secret-key header against the env.LIVE_SERVER_SECRET_KEY environment variable, returning a 401 response on mismatch.

import express from "express";
import { requireSecretKey } from "@/lib/auth-middleware";

const router = express.Router();

router.post("/admin/trigger", requireSecretKey, (req, res) => {
  // secret key validated – proceed safely
  res.json({ status: "ok" });
});

JWT-Based Invitation Tokens

Project and workspace invitations use cryptographically signed JWT tokens to verify email-based invites. When creating an invitation in apps/api/plane/app/views/project/invite.py, Plane encodes a payload containing the invitee's email and timestamp using jwt.encode() with the Django SECRET_KEY and HS256 algorithm.

The resulting token is stored on the ProjectMemberInvite model and validated when the invitee accepts, ensuring only intended recipients can join workspaces.

token = jwt.encode(
    {"email": email, "timestamp": datetime.now().timestamp()},
    settings.SECRET_KEY,
    algorithm="HS256",
)

invite = ProjectMemberInvite.objects.create(
    email=email,
    workspace_id=workspace.id,
    token=token,
    # …

)

Frontend Authentication Layer

The React frontend centralizes routing logic through AuthenticationWrapper in apps/web/core/lib/wrappers/authentication-wrapper.tsx. This component checks the user store, profile data, and workspace selection status, then redirects to onboarding, workspace selection, or login pages based on authentication state.

For third-party OAuth providers like Google and GitHub, the OAuthOptions component in packages/ui/src/oauth/oauth-options.tsx renders available authentication buttons and forwards click events to backend handlers that manage the actual token exchange.

import { AuthenticationWrapper, EPageTypes } from "@/helpers/authentication.helper";

export default function Dashboard() {
  return (
    <AuthenticationWrapper pageType={EPageTypes.AUTHENTICATED}>
      {/* Dashboard UI – only rendered for logged‑in users */}
      <h1>Welcome to Plane</h1>
    </AuthenticationWrapper>
  );
}

Summary

Plane's security model implements distinct authentication strategies tailored to different interaction patterns:

  • API Key Authentication: Custom middleware validates X-Api-Key headers against database tokens with automatic OpenAPI documentation in apps/api/plane/utils/openapi/auth.py
  • Session Management: Extended Django sessions disable CSRF for APIs while the frontend manages CSRF tokens separately via AuthService
  • Internal Service Protection: Express middleware enforces shared secret validation for live-server endpoints using requireSecretKey
  • Invitation Security: JWT tokens signed with Django's SECRET_KEY prevent unauthorized workspace access through the ProjectMemberInvite model
  • Frontend Routing: React wrappers enforce authentication state at the UI layer before rendering protected components

Frequently Asked Questions

How does Plane authenticate API requests?

Plane authenticates API requests through the APIKeyAuthentication class in apps/api/plane/app/middleware/api_authentication.py. This middleware extracts the X-Api-Key header, validates it against the APIToken model, and updates the last_used timestamp. For browser-based access, it falls back to Django session authentication via BaseSessionAuthentication in apps/api/plane/authentication/session.py.

What CSRF protection does Plane use for web forms?

Plane implements CSRF protection through a token service defined in packages/services/src/auth/auth.service.ts. The frontend requests a fresh token from /auth/get-csrf-token/ and attaches it to POST requests via the X-CSRFTOKEN header. The API layer disables CSRF enforcement for direct API calls while maintaining protection for browser-based form submissions.

How are project invitations secured in Plane?

Project invitations use JWT tokens generated in apps/api/plane/app/views/project/invite.py. These tokens encode the invitee's email and a timestamp, signed with Django's SECRET_KEY using the HS256 algorithm. The token is stored on the ProjectMemberInvite model and validated upon acceptance to ensure only the intended recipient can join the workspace.

What authentication methods are available for self-hosted Plane instances?

Self-hosted instances support API key authentication for programmatic access, Django session authentication for web users, and optional OAuth providers (Google, GitHub) through the OAuthOptions component. Internal services require the live-server-secret-key header configured via the LIVE_SERVER_SECRET_KEY environment variable.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →