makeplane/plane · error · AuthenticationFailed

Given API token is not valid

Error message

Given API token is not valid

What it means

Identical logic to the api/ counterpart but in apps/api/plane/app/middleware/api_authentication.py (the 'app' app's auth middleware). validate_api_token looks up an active, non-expired APIToken owned by an active user; APIToken.DoesNotExist raises DRF AuthenticationFailed -> HTTP 401. Same contract, different app namespace.

Source

Thrown at apps/api/plane/app/middleware/api_authentication.py:38

    """

    www_authenticate_realm = "api"
    media_type = "application/json"
    auth_header_name = "X-Api-Key"

    def get_api_token(self, request):
        return request.headers.get(self.auth_header_name)

    def validate_api_token(self, token):
        try:
            api_token = APIToken.objects.get(
                Q(Q(expired_at__gt=timezone.now()) | Q(expired_at__isnull=True)),
                token=token,
                is_active=True,
                user__is_active=True,
            )
        except APIToken.DoesNotExist:
            raise AuthenticationFailed("Given API token is not valid")

        # save api token last used
        api_token.last_used = timezone.now()
        api_token.save(update_fields=["last_used"])
        return (api_token.user, api_token.token)

    def authenticate(self, request):
        token = self.get_api_token(request=request)
        if not token:
            return None

        # Validate the API token
        user, token = self.validate_api_token(token)
        return user, token

View on GitHub (pinned to 1c8a60f858)

Solutions

  1. Generate a fresh token and confirm the endpoint belongs to the expected app.
  2. Ensure the token's user is active and not expired.
  3. Strip whitespace/newlines from the header value.
  4. Check logs for which app's middleware rejected it if the message alone is ambiguous.

Example fix

# before
client = Plane(api_key='\n<revoked-token>\n')

# after
client = Plane(api_key=os.environ['PLANE_API_KEY'].strip())
Defensive patterns

Strategy: try-catch

Validate before calling

token = os.environ['PLANE_API_KEY'].strip()
assert token and not token.startswith(' '), 'clean token required'

Try / catch

try:
    call_app_endpoint(token)
except AuthenticationFailed as e:
    if 'not valid' in str(e):
        token = regenerate_token(); call_app_endpoint(token)

Prevention

When it happens

Trigger: Hitting an endpoint served by the 'app' app with a token that is invalid, inactive, expired, or whose user is inactive.

Common situations: Token rotated in one place but used against an 'app' endpoint elsewhere; cross-workspace token misuse; revoked token still cached by a client.

Related errors


AI-assisted analysis of makeplane/plane@1c8a60f858 (2026-08-12). Data as JSON: /api/errors/9e2bc2e3f11203de. Report an issue: GitHub.