{"record":{"id":"9fa04cc7afb3f4f8","repo":"nocobase/nocobase","slug":"failed-to-register-oauth-client-formatoautherror","errorCode":null,"errorMessage":"Failed to register OAuth client (formatOauthError with response data and status)","messagePattern":"Failed to register OAuth client \\(formatOauthError with response data and status\\)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/cli/src/lib/env-auth.ts","lineNumber":434,"sourceCode":"      {\n        operation: 'Registering OAuth client',\n        onRetry: (message) => updateTask(message),\n      },\n    );\n  } catch (error: any) {\n    throw new Error(\n      formatOauthFetchFailure('Failed to register OAuth client.', {\n        envName: options.envName,\n        baseUrl: options.baseUrl,\n        url: metadata.registration_endpoint,\n        rawMessage: error?.message,\n      }),\n    );\n  }\n  const data = await parseJsonResponse(response);\n\n  if (!response.ok) {\n    throw new Error(formatOauthError('Failed to register OAuth client', data, response.status));\n  }\n\n  if (!data || typeof data !== 'object' || typeof data.client_id !== 'string') {\n    throw new Error('OAuth client registration succeeded but no client_id was returned.');\n  }\n\n  return {\n    clientId: data.client_id as string,\n  };\n}\n\nfunction encodeBase64Url(input: Buffer) {\n  return input\n    .toString('base64')\n    .replace(/\\+/g, '-')\n    .replace(/\\//g, '_')\n    .replace(/=+$/g, '');\n}","sourceCodeStart":416,"sourceCodeEnd":452,"githubUrl":"https://github.com/nocobase/nocobase/blob/fa42722fefe44265490dff2c27d79e2882bce4fa/packages/core/cli/src/lib/env-auth.ts#L416-L452","documentation":"Thrown by registerOauthClient when the dynamic client registration endpoint responded with a non-2xx status. The response body (parsed by parseJsonResponse) and HTTP status are formatted via formatOauthError, which prefers the RFC 7591 error / error_description fields, falling back to the raw body text or 'HTTP <status>'. This means the server actively rejected the registration request.","triggerScenarios":"POST to registration_endpoint returning 4xx/5xx, e.g. 401 unauthorized (registration requires an initial access token), 400 invalid_client_metadata (malformed redirect URIs or scope), 403 forbidden (registration disabled on the server), or 502 from a reverse proxy.","commonSituations":"OAuth server has dynamic client registration disabled; server requires an initial access token the CLI does not send; reverse proxy (nginx) returning 404/502 because the endpoint path is rewritten; server version changed its registration API; scope/redirect_uri values rejected by server policy.","solutions":["Read the error/error_description appended to the message and fix the reported metadata issue (e.g. invalid redirect_uri or scope).","Confirm the OAuth server permits dynamic client registration (RFC 7591); if it requires an initial access token, register the client manually and configure the client_id instead.","Check the server/proxy logs for the 4xx/5xx status shown after 'HTTP' in the message to identify infrastructure issues.","Re-run `nb env auth <env>` after correcting server configuration or upgrading the server."],"exampleFix":"// server-side: enable dynamic registration or provide static credentials\n// before\n// registration_endpoint returns 403 { \"error\": \"access_denied\" }\n// after (server config)\n// oauth: { allowDynamicRegistration: true }  // or pre-registered client_id used instead","handlingStrategy":"try-catch","validationCode":"// check the server advertises dynamic registration before attempting it\nconst meta = await (await fetch(`${base}/.well-known/oauth-authorization-server`)).json();\nif (!meta.registration_endpoint) {\n  throw new Error('Server does not support dynamic client registration; configure a client_id manually.');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await registerOauthClient(options);\n} catch (err) {\n  const msg = String(err.message);\n  if (/HTTP (401|403)/.test(msg)) {\n    console.error('Dynamic registration rejected: register the client manually or enable it server-side.');\n  } else throw err;\n}","preventionTips":["Confirm the OAuth server allows RFC 7591 dynamic client registration before using CLI OAuth login.","Inspect metadata.registration_endpoint availability up front.","Keep server and CLI versions aligned.","Check reverse-proxy rules don't block or rewrite the registration path."],"tags":["oauth","http-error","cli","rfc7591"],"backgroundTag":"oauth-registration-rejected","analyzedSha":"fa42722fefe44265490dff2c27d79e2882bce4fa","analyzedAt":"2026-09-01T00:54:31.202Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}