justauth/JustAuth · error · AuthException

${errmsg}

Error message

${errmsg}

What it means

AbstractAuthDingtalkRequest.getUserInfo posts the tmp_auth_code to https://oapi.dingtalk.com/sns/getuserinfo_bycode and checks the errcode field. Any non-zero errcode (plus errmsg) is rethrown as an AuthException carrying DingTalk's own message. Common codes: invalid/expired tmp_auth_code, signature problems, or wrong appId/appSecret on the qs/sns side.

Source

Thrown at src/main/java/me/zhyd/oauth/request/AbstractAuthDingtalkRequest.java:49

    public AbstractAuthDingtalkRequest(AuthConfig config, AuthSource source, AuthStateCache authStateCache) {
        super(config, source, authStateCache);
    }

    @Override
    public AuthToken getAccessToken(AuthCallback authCallback) {
        return AuthToken.builder().accessCode(authCallback.getCode()).build();
    }

    @Override
    public AuthUser getUserInfo(AuthToken authToken) {
        String code = authToken.getAccessCode();
        JSONObject param = new JSONObject();
        param.put("tmp_auth_code", code);
        String response = new HttpUtils(config.getHttpConfig()).post(userInfoUrl(authToken), param.toJSONString()).getBody();
        JSONObject object = JSON.parseObject(response);
        if (object.getIntValue("errcode") != 0) {
            throw new AuthException(object.getString("errmsg"));
        }
        object = object.getJSONObject("user_info");
        AuthToken token = AuthToken.builder()
            .openId(object.getString("openid"))
            .unionId(object.getString("unionid"))
            .build();
        return AuthUser.builder()
            .rawUserInfo(object)
            .uuid(object.getString("unionid"))
            .nickname(object.getString("nick"))
            .username(object.getString("nick"))
            .gender(AuthUserGender.UNKNOWN)
            .source(source.toString())
            .token(token)
            .build();
    }

    /**

View on GitHub (pinned to 694bbf1b01)

Solutions

  1. Exchange the tmp_auth_code immediately upon callback — it is one-time and expires within minutes; do not retry with the same code.
  2. Verify the DingTalk scan-login app's appId/appSecret in AuthConfig match the app created in the DingTalk open platform.
  3. Log the raw response before parsing to capture the exact errcode; handle errcode by re-prompting the QR scan when the code is invalid.
  4. If the message mentions signature, prefer the DingTalk-signed request variants (AuthDingTalkRequest with sdk-based signing) instead of the raw POST.

Example fix

// before
// callback endpoint retries on failure with the same code -> errmsg 'code been used'

// after
// process the callback exactly once, store the result, and on AuthException re-run the QR flow:
try { return request.login(callback); }
catch (AuthException e) { log.warn("dingtalk login failed: {}", e.getMessage()); return restartScanLogin(); }
Defensive patterns

Strategy: try-catch

Validate before calling

if (StringUtils.isEmpty(callback.getCode())) { throw new IllegalArgumentException("DingTalk callback missing code"); }

Try / catch

try { return request.login(callback); } catch (AuthException e) { log.warn("DingTalk userinfo errcode: {}", e.getMessage()); return restartQrLogin(); }

Prevention

When it happens

Trigger: Calling login() or getUserInfo() where the code is stale (tmp_auth_code is single-use and short-lived), was already consumed, or the DingTalk app credentials are wrong; clock skew or network proxies mangling the POST body.

Common situations: User sits on the callback page before the server processes it and the code expires; retrying the callback (idempotency issue) reuses a consumed code; wrong appId/secret configured for the scan-login app; DingTalk API changes to getuserinfo_bycode (which historically required a signature).

Related errors


AI-assisted analysis of justauth/JustAuth@694bbf1b01 (2026-08-14). Data as JSON: /api/errors/851318b2881fcfbd. Report an issue: GitHub.