makeplane/plane · error · AuthenticationFailed

Given API token is not valid

Error message

Given API token is not valid

What it means

validate_api_token queries APIToken with conditions: token matches, is_active=True, user__is_active=True, and (expired_at > now OR expired_at is null). If APIToken.DoesNotExist is raised, the DRF AuthenticationFailed is thrown with this message, producing an HTTP 401. This is the standard API-token auth path in apps/api/plane/api/middleware.

Source

Thrown at apps/api/plane/api/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. Regenerate the API token in the workspace settings and update the client.
  2. Confirm the token's user account is active and not suspended.
  3. Check the token's expired_at; if set and passed, issue a new token.
  4. Verify the header name matches auth_header_name (default X-API-Key) and the value has no leading/trailing whitespace.

Example fix

# before
curl -H 'X-API-Key: stale-or-revoked' https://api/v1/...

# after
curl -H 'X-API-Key: <newly generated token>' https://api/v1/...
Defensive patterns

Strategy: try-catch

Validate before calling

# before each call, ensure token is non-empty and recently issued
import os
assert os.environ['PLANE_API_KEY'].strip(), 'missing API token'

Try / catch

try:
    client.get('/work-items/')
except AuthenticationFailed as e:
    if str(e) == 'Given API token is not valid':
        rotate_token(); retry()

Prevention

When it happens

Trigger: Request with X-API-Key header set to a token that is wrong, revoked (is_active=False), owned by a deactivated user, or past expired_at with no null expiry.

Common situations: Rotated/revoked token still used by an integration; clock skew between client and server expiring the token early; user deactivated but external script still runs; typo in the header value.

Related errors


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