makeplane/plane · error · AuthenticationException

5115|5120|5121|5123|5104

5115|5120|5121|5123|5104

Error message

str(code)

What it means

Raised in OauthAdapter.get_user_token (oauth.py:84) when the POST to the provider's token URL raises requests.RequestException (network error or non-2xx via raise_for_status). The error code/message are dynamic: code = self.authentication_error_code(), so it resolves to GOOGLE_OAUTH_PROVIDER_ERROR (5115), GITHUB_OAUTH_PROVIDER_ERROR (5120), GITLAB_OAUTH_PROVIDER_ERROR (5121), GITEA_OAUTH_PROVIDER_ERROR (5123), or OAUTH_NOT_CONFIGURED (5104) for unknown providers. The message is str(code) — the constant NAME, not a human string.

Source

Thrown at apps/api/plane/authentication/adapter/oauth.py:84

    def get_user_info_url(self):
        return self.userinfo_url

    def authenticate(self):
        self.set_token_data()
        self.set_user_data()
        return self.complete_login_or_signup()

    def get_user_token(self, data, headers=None):
        try:
            headers = headers or {}
            response = requests.post(self.get_token_url(), data=data, headers=headers)
            response.raise_for_status()
            return response.json()
        except requests.RequestException:
            self.logger.warning("Error getting user token")
            code = self.authentication_error_code()
            raise AuthenticationException(error_code=AUTHENTICATION_ERROR_CODES[code], error_message=str(code))

    def get_user_response(self):
        try:
            headers = {"Authorization": f"Bearer {self.token_data.get('access_token')}"}
            response = requests.get(self.get_user_info_url(), headers=headers)
            response.raise_for_status()
            return response.json()
        except requests.RequestException:
            # Do not log headers here: they carry the access token
            self.logger.warning("Error getting user response")
            code = self.authentication_error_code()
            raise AuthenticationException(error_code=AUTHENTICATION_ERROR_CODES[code], error_message=str(code))

    def set_user_data(self, data):
        self.user_data = data

    def create_update_account(self, user):
        try:

View on GitHub (pinned to 1c8a60f858)

Solutions

  1. Check the backend log line 'Error getting user token' alongside provider docs for the failing token exchange (most often an expired/reused auth code or bad client_secret).
  2. Verify OAUTH_CLIENT_SECRET / *_CLIENT_SECRET and redirect_uri match the provider app configuration exactly.
  3. Confirm network egress from the API container to the provider's token URL is allowed.
  4. If self.provider is unrecognized, the code falls back to OAUTH_NOT_CONFIGURED — register the provider in authentication_error_code().

Example fix

# before: client_secret typo -> provider returns 401 -> RequestException -> 5120
# GITHUB_CLIENT_SECRET=correct-secret-value   (env / instance config)
# after: ensure token URL is reachable and credentials are correct
Defensive patterns

Strategy: retry

Validate before calling

import requests

def token_endpoint_reachable(token_url: str, timeout: float = 5.0) -> bool:
    try:
        # connectivity probe only; do NOT send real code/secret here
        return requests.options(token_url, timeout=timeout).status_code < 500
    except requests.RequestException:
        return False

Try / catch

from plane.authentication.adapter.error import AuthenticationException

try:
    adapter.get_user_token(data)
except AuthenticationException as e:
    if e.error_code in (5115, 5120, 5121, 5123, 5104):
        log_oauth_token_failure(provider=adapter.provider, code=e.error_code)
        prompt_user_retry()
    else:
        raise

Prevention

When it happens

Trigger: OAuth callback flow: the authorization code is exchanged at the provider's token endpoint. If the request times out, the endpoint returns 4xx/5xx, DNS fails, or the provider is unreachable, RequestException is caught and AuthenticationException is raised. Which numeric code you get depends entirely on self.provider.

Common situations: Expired or replayed authorization code (providers return 400 on second use), wrong client_secret (provider returns 401), redirect_uri mismatch, network egress restrictions to the OAuth provider, or the provider's token endpoint is down.

Related errors


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