{"record":{"id":"0387cbe18624a9ca","repo":"justauth/JustAuth","slug":"jsonobject-tojsonstring-response","errorCode":null,"errorMessage":"JSONObject.toJSONString(response)","messagePattern":"JSONObject\\.toJSONString\\(response\\)","errorType":"exception","errorClass":"AuthException","httpStatus":null,"severity":"error","filePath":"src/main/java/me/zhyd/oauth/request/AuthDingTalkV2Request.java","lineNumber":62,"sourceCode":"            .queryParam(\"org_type\", config.getDingTalkOrgType())\n            .queryParam(\"corpId\", config.getDingTalkCorpId())\n            .queryParam(\"exclusiveLogin\", config.isDingTalkExclusiveLogin())\n            .queryParam(\"exclusiveCorpId\", config.getDingTalkExclusiveCorpId())\n            .queryParam(\"state\", getRealState(state))\n            .build();\n    }\n\n    @Override\n    public AuthToken getAccessToken(AuthCallback authCallback) {\n        Map<String, String> params = new HashMap<>();\n        params.put(\"grantType\", \"authorization_code\");\n        params.put(\"clientId\", config.getClientId());\n        params.put(\"clientSecret\", config.getClientSecret());\n        params.put(\"code\", authCallback.getCode());\n        String response = new HttpUtils(config.getHttpConfig()).post(this.source.accessToken(), JSONObject.toJSONString(params)).getBody();\n        JSONObject accessTokenObject = JSONObject.parseObject(response);\n        if (!accessTokenObject.containsKey(\"accessToken\")) {\n            throw new AuthException(JSONObject.toJSONString(response), source);\n        }\n        return AuthToken.builder()\n            .accessToken(accessTokenObject.getString(\"accessToken\"))\n            .refreshToken(accessTokenObject.getString(\"refreshToken\"))\n            .expireIn(accessTokenObject.getIntValue(\"expireIn\"))\n            .corpId(accessTokenObject.getString(\"corpId\"))\n            .build();\n    }\n\n    @Override\n    public AuthUser getUserInfo(AuthToken authToken) {\n        HttpHeader header = new HttpHeader();\n        header.add(\"x-acs-dingtalk-access-token\", authToken.getAccessToken());\n\n        String response = new HttpUtils(config.getHttpConfig()).get(this.source.userInfo(), null, header, false).getBody();\n        JSONObject object = JSONObject.parseObject(response);\n\n        authToken.setOpenId(object.getString(\"openId\"));","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/justauth/JustAuth/blob/694bbf1b010d93404e3bfb4824d90e9ddfaebebb/src/main/java/me/zhyd/oauth/request/AuthDingTalkV2Request.java#L44-L80","documentation":"The DingTalk v2 adapter posts grantType=authorization_code and expects an 'accessToken' field in the JSON response; when that key is absent it throws AuthException whose message is the entire raw response body. So the exception text is DingTalk's own error payload (errcode/errmsg style), which tells you why the exchange failed.","triggerScenarios":"getAccessToken(AuthCallback) with a wrong clientId/clientSecret pair, an authorization code that was already redeemed or expired (DingTalk codes are single-use and short-lived), or a server-side error where DingTalk returns errcode without accessToken.","commonSituations":"User refreshes the callback page causing the code to be exchanged twice; DingTalk app credentials rotated; system clock skew; or dev environment reaching DingTalk through a proxy that mangles the POST body.","solutions":["Read the thrown message - it is DingTalk's raw JSON, e.g. {\"errcode\":40035,\"errmsg\":\"invalid code\"} - and act on the errmsg.","Ensure the code from authCallback.getCode() is exchanged exactly once, immediately after redirect (store state to dedupe).","Verify the DingTalk app's clientId (AppKey)/clientSecret (AppSecret) match the current credentials.","If errmsg mentions IP restrictions, add your server's egress IP to the DingTalk app's server whitelist."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    return dingTalkRequest.getAccessToken(callback);\n} catch (AuthException e) {\n    // message is DingTalk's raw JSON body, e.g. {\"errcode\":40035,\"errmsg\":\"invalid code\"}\n    log.warn(\"DingTalk token error: {}\", e.getErrorMsg());\n    if (e.getErrorMsg() != null && e.getErrorMsg().contains(\"invalid code\")) {\n        return reauthorizeResponse();\n    }\n    throw e;\n}","preventionTips":["Exchange the DingTalk authCode within seconds of the callback and never twice - it is single-use.","Keep AppKey/AppSecret in sync with the DingTalk developer console after rotations.","Whitelist your server egress IPs in the DingTalk app if you see IP-related errmsg values."],"tags":["oauth","dingtalk","justauth","api-error","token-exchange"],"backgroundTag":null,"analyzedSha":"694bbf1b010d93404e3bfb4824d90e9ddfaebebb","analyzedAt":"2026-08-14T15:16:59.945Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}