{"record":{"id":"7f64c3880a547692","repo":"makeplane/plane","slug":"5115-5120-5121-5123-5104","errorCode":"5115|5120|5121|5123|5104","errorMessage":"str(code)","messagePattern":"str\\(code\\)","errorType":"exception","errorClass":"AuthenticationException","httpStatus":null,"severity":"error","filePath":"apps/api/plane/authentication/adapter/oauth.py","lineNumber":84,"sourceCode":"\n    def get_user_info_url(self):\n        return self.userinfo_url\n\n    def authenticate(self):\n        self.set_token_data()\n        self.set_user_data()\n        return self.complete_login_or_signup()\n\n    def get_user_token(self, data, headers=None):\n        try:\n            headers = headers or {}\n            response = requests.post(self.get_token_url(), data=data, headers=headers)\n            response.raise_for_status()\n            return response.json()\n        except requests.RequestException:\n            self.logger.warning(\"Error getting user token\")\n            code = self.authentication_error_code()\n            raise AuthenticationException(error_code=AUTHENTICATION_ERROR_CODES[code], error_message=str(code))\n\n    def get_user_response(self):\n        try:\n            headers = {\"Authorization\": f\"Bearer {self.token_data.get('access_token')}\"}\n            response = requests.get(self.get_user_info_url(), headers=headers)\n            response.raise_for_status()\n            return response.json()\n        except requests.RequestException:\n            # Do not log headers here: they carry the access token\n            self.logger.warning(\"Error getting user response\")\n            code = self.authentication_error_code()\n            raise AuthenticationException(error_code=AUTHENTICATION_ERROR_CODES[code], error_message=str(code))\n\n    def set_user_data(self, data):\n        self.user_data = data\n\n    def create_update_account(self, user):\n        try:","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/makeplane/plane/blob/1c8a60f858d8472aa56e29994ec1c7926da2c6ce/apps/api/plane/authentication/adapter/oauth.py#L66-L102","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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).","Verify OAUTH_CLIENT_SECRET / *_CLIENT_SECRET and redirect_uri match the provider app configuration exactly.","Confirm network egress from the API container to the provider's token URL is allowed.","If self.provider is unrecognized, the code falls back to OAUTH_NOT_CONFIGURED — register the provider in authentication_error_code()."],"exampleFix":"# before: client_secret typo -> provider returns 401 -> RequestException -> 5120\n# GITHUB_CLIENT_SECRET=correct-secret-value   (env / instance config)\n# after: ensure token URL is reachable and credentials are correct","handlingStrategy":"retry","validationCode":"import requests\n\ndef token_endpoint_reachable(token_url: str, timeout: float = 5.0) -> bool:\n    try:\n        # connectivity probe only; do NOT send real code/secret here\n        return requests.options(token_url, timeout=timeout).status_code < 500\n    except requests.RequestException:\n        return False","typeGuard":null,"tryCatchPattern":"from plane.authentication.adapter.error import AuthenticationException\n\ntry:\n    adapter.get_user_token(data)\nexcept AuthenticationException as e:\n    if e.error_code in (5115, 5120, 5121, 5123, 5104):\n        log_oauth_token_failure(provider=adapter.provider, code=e.error_code)\n        prompt_user_retry()\n    else:\n        raise","preventionTips":["Keep OAuth credentials in instance config and validate them at deploy time.","Ensure network egress to the provider's token URL from the API container.","Do not reuse authorization codes — each OAuth callback exchanges a fresh code."],"tags":["oauth","network","authentication","provider-error","requests"],"backgroundTag":null,"analyzedSha":"1c8a60f858d8472aa56e29994ec1c7926da2c6ce","analyzedAt":"2026-08-12T14:44:31.636Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}