{"record":{"id":"dfcf07f1d0978d80","repo":"alibaba/nacos","slug":"token-endpoint-not-configured","errorCode":null,"errorMessage":"Token endpoint not configured","messagePattern":"Token endpoint not configured","errorType":"exception","errorClass":"AccessException","httpStatus":null,"severity":"error","filePath":"plugin-default-impl/nacos-oidc-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/oidc/authenticate/AuthorizationCodeHandler.java","lineNumber":218,"sourceCode":"            throw e;\n        } catch (Exception e) {\n            LOGGER.error(\"Failed to exchange code for tokens\", e);\n            throw new AccessException(\"Authentication failed: \" + e.getMessage());\n        }\n    }\n    \n    /**\n     * Exchange authorization code for OIDC tokens.\n     *\n     * @param code        authorization code\n     * @param redirectUri redirect URI\n     * @return OIDC tokens\n     * @throws Exception if exchange fails\n     */\n    private OIDCTokens exchangeCodeForTokens(String code, String redirectUri) throws Exception {\n        String tokenEndpoint = metadataProvider.getMetadata().getTokenEndpoint();\n        if (StringUtils.isBlank(tokenEndpoint)) {\n            throw new AccessException(\"Token endpoint not configured\");\n        }\n        \n        // Build token request\n        AuthorizationCode authCode = new AuthorizationCode(code);\n        AuthorizationGrant grant = new AuthorizationCodeGrant(authCode, URI.create(redirectUri));\n        \n        // Client authentication\n        ClientAuthentication clientAuth = new ClientSecretBasic(\n            new ClientID(config.getClientId()),\n            new Secret(config.getClientSecret()));\n        \n        // Send token request\n        TokenRequest tokenRequest = new TokenRequest(\n            URI.create(tokenEndpoint),\n            clientAuth,\n            grant);\n        \n        TokenResponse tokenResponse =","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/plugin-default-impl/nacos-oidc-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/oidc/authenticate/AuthorizationCodeHandler.java#L200-L236","documentation":"Thrown by AuthorizationCodeHandler.exchangeCodeForTokens when the OIDC provider metadata's token_endpoint is blank. The token endpoint is obtained from the discovery document (OidcProviderMetadataProvider.getMetadata()), not configured directly. Without it Nacos cannot POST the authorization code to exchange it for ID/access tokens.","triggerScenarios":"OIDC discovery ran but the IdP's .well-known/openid-configuration JSON omitted the token_endpoint field, or discovery has not completed yet and metadata returns all-null fields, or the issuer-uri points at a document that is not a real OIDC discovery doc.","commonSituations":"Using a non-OIDC OAuth2 provider that has no token_endpoint; pointing issuer-uri at a partial/custom discovery doc; discovery endpoint returned 200 but a truncated body so all endpoints are null; the provider only supports a different flow (e.g. implicit only).","solutions":["Verify the IdP discovery document at <issuer-uri>/.well-known/openid-configuration actually contains a non-empty token_endpoint field (curl it and inspect the JSON).","Confirm issuer-uri is correct and points to the OIDC root, not a sub-path or the JWKS URL.","If discovery is broken, ensure OidcProviderMetadataProvider successfully discovered (check the log line 'OIDC configuration discovered: jwksUri=...'); a missing log means discovery failed and metadata is null.","Use a fully OIDC-compliant IdP (Keycloak, Auth0, Google) that publishes token_endpoint."],"exampleFix":"// before: issuer-uri points to a doc without token_endpoint\nnacos.plugin.auth.oidc.issuer-uri=https://example.com/oauth2\n// after: point at the OIDC issuer root whose discovery doc includes token_endpoint\nnacos.plugin.auth.oidc.issuer-uri=https://keycloak.example.com/realms/myrealm","handlingStrategy":"validation","validationCode":"// Before triggering authorization-code flow, confirm discovery populated a token endpoint\nOidcProviderMetadata meta = metadataProvider.getMetadata();\nif (StringUtils.isBlank(meta.getTokenEndpoint())) {\n    throw new IllegalStateException(\n        \"IdP discovery doc has no token_endpoint; authorize-code flow unavailable\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    handler.exchangeCodeForUser(code, state, redirectUri);\n} catch (AccessException e) {\n    if (e.getMessage().contains(\"Token endpoint not configured\")) {\n        // discovery issue — surface a clear config error, do not retry the same code\n        log.error(\"OIDC token endpoint missing from discovery; check issuer-uri and IdP config\");\n    }\n    throw e;\n}","preventionTips":["Validate the discovery document manually with curl before enabling the authorization-code flow.","Use an OIDC-certified IdP that always publishes token_endpoint.","Log the discovered metadata at startup so missing endpoints are visible early."],"tags":["oidc","config","authentication","authorization-code","discovery"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}