{"record":{"id":"cbbfc90599802f02","repo":"nextauthjs/next-auth","slug":"todo-authorization-server-did-not-provide-a-token","errorCode":null,"errorMessage":"TODO: Authorization server did not provide a token endpoint.","messagePattern":"TODO: Authorization server did not provide a token endpoint\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"packages/core/src/lib/actions/callback/oauth/callback.ts","lineNumber":72,"sourceCode":"  let as: o.AuthorizationServer\n\n  const { token, userinfo } = provider\n  // Falls back to authjs.dev if the user only passed params\n  if (\n    (!token?.url || token.url.host === \"authjs.dev\") &&\n    (!userinfo?.url || userinfo.url.host === \"authjs.dev\")\n  ) {\n    // We assume that issuer is always defined as this has been asserted earlier\n\n    const issuer = new URL(provider.issuer!)\n    const discoveryResponse = await o.discoveryRequest(issuer, {\n      [o.allowInsecureRequests]: true,\n      [o.customFetch]: provider[customFetch],\n    })\n    as = await o.processDiscoveryResponse(issuer, discoveryResponse)\n\n    if (!as.token_endpoint)\n      throw new TypeError(\n        \"TODO: Authorization server did not provide a token endpoint.\"\n      )\n\n    if (!as.userinfo_endpoint)\n      throw new TypeError(\n        \"TODO: Authorization server did not provide a userinfo endpoint.\"\n      )\n  } else {\n    as = {\n      issuer: provider.issuer ?? \"https://authjs.dev\", // TODO: review fallback issuer\n      token_endpoint: token?.url.toString(),\n      userinfo_endpoint: userinfo?.url.toString(),\n    }\n  }\n\n  const client: o.Client = {\n    client_id: provider.clientId,\n    ...provider.client,","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/nextauthjs/next-auth/blob/a1a16a5a7780488c7449feece410033f445d0b31/packages/core/src/lib/actions/callback/oauth/callback.ts#L54-L90","documentation":"During OAuth/OIDC discovery, Auth.js processes the issuer's well-known configuration with the openid-client library and requires a token_endpoint to exchange the authorization code. If the discovery document lacks one, a TypeError with this (work-in-progress) message is thrown. It almost always means the provider's discovery metadata is incomplete or the issuer URL is wrong.","triggerScenarios":"Provider configured with an `issuer` whose /.well-known/openid-configuration (or oauth-authorization-server) response does not include token_endpoint — e.g. an OAuth 2.0 (non-OIDC) server, a misconfigured issuer URL that hits a gateway returning partial metadata, or a stub/mock server.","commonSituations":"Pointing issuer at a wrong base URL so discovery returns an HTML page or minimal config; using providers that only implement authorization + userinfo without a token endpoint; wellKnown omitted while issuer serves partial metadata; corporate proxies returning a cached/trimmed document.","solutions":["Verify {issuer}/.well-known/openid-configuration in a browser/curl and confirm it contains token_endpoint","Correct the provider `issuer` URL (trailing-slash, path prefix, environment hostname) so real metadata is fetched","If the server truly has no token endpoint, configure wellKnown/token_endpoint explicitly or provide authorization/token endpoints manually in the provider config","Use a well-known provider preset (e.g. from @auth/core/providers) that declares endpoints directly, skipping discovery"],"exampleFix":"// before\nproviders: [Github({ issuer: \"https://auth.example.com\" })] // partial discovery\n// after\nproviders: [{\n  id: \"github\",\n  type: \"oauth\",\n  authorization: { url: \"https://github.com/login/oauth/authorize\" },\n  token: \"https://github.com/login/oauth/access_token\",\n  userinfo: \"https://api.github.com/user\",\n  ...\n}]","handlingStrategy":"validation","validationCode":"const issuer = \"https://sso.acme.com\"\nconst doc = await fetch(`${issuer}/.well-known/openid-configuration`).then(r => r.json())\nif (!doc.token_endpoint) throw new Error(`Issuer ${issuer} has no token_endpoint`)","typeGuard":"function hasTokenEndpoint(as: unknown): as is { token_endpoint: string } {\n  return typeof as === \"object\" && as !== null && typeof (as as any).token_endpoint === \"string\"\n}","tryCatchPattern":"try {\n  await signIn(providerId)\n} catch (e) {\n  if ((e as Error).message.includes(\"did not provide a token endpoint\")) {\n    // verify issuer URL or declare token endpoint manually in provider config\n  }\n}","preventionTips":["Curl the well-known discovery URL after configuring any new issuer","Provide token/authorization/userinfo endpoints explicitly for OAuth2-only servers","Avoid trailing slashes and path mistakes in issuer URLs","Pin a provider preset instead of raw issuer discovery when metadata is known-bad"],"tags":["oauth","oidc","discovery","configuration"],"backgroundTag":"oauth-discovery-incomplete","analyzedSha":"a1a16a5a7780488c7449feece410033f445d0b31","analyzedAt":"2026-08-28T21:52:38.200Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}