justauth/JustAuth · error · AuthException

5003

5003

Error message

Unsupported operation

What it means

For the DINGTALK source, the accessToken() endpoint deliberately throws AuthException 5003 (Unsupported operation). DingTalk scan-login (qrconnect) does not use a server-side OAuth access-token exchange: the tmp_auth_code from the callback is sent directly to the getuserinfo_bycode endpoint. Calling any flow step that needs source.accessToken() therefore fails by design.

Source

Thrown at src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java:102

        }

        @Override
        public Class<? extends AuthDefaultRequest> getTargetClass() {
            return AuthGiteeRequest.class;
        }
    },
    /**
     * 钉钉扫码登录
     */
    DINGTALK {
        @Override
        public String authorize() {
            return "https://oapi.dingtalk.com/connect/qrconnect";
        }

        @Override
        public String accessToken() {
            throw new AuthException(AuthResponseStatus.UNSUPPORTED);
        }

        @Override
        public String userInfo() {
            return "https://oapi.dingtalk.com/sns/getuserinfo_bycode";
        }

        @Override
        public Class<? extends AuthDefaultRequest> getTargetClass() {
            return AuthDingTalkRequest.class;
        }
    },
    /**
     * 新版钉钉扫码登录
     */
    DINGTALK_V2 {
        @Override
        public String authorize() {

View on GitHub (pinned to 694bbf1b01)

Solutions

  1. Use the DingTalk-specific flow: getAccessToken(callback) just wraps the code, and getUserInfo(token) exchanges the tmp_auth_code via getuserinfo_bycode — call login(callback) or getUserInfo directly.
  2. Do not call refresh() or revoke() on DingTalk requests; guard those calls by provider type.
  3. If you truly need token-based DingTalk APIs, use DingTalk's own SDK instead of this source.

Example fix

// before
AuthToken token = request.refresh(oldToken).getData(); // -> source.refresh()/accessToken() -> 5003

// after (DingTalk has no token endpoint; use the one-shot code exchange)
AuthResponse<AuthUser> resp = request.login(AuthCallback.builder().code(code).build());
Defensive patterns

Strategy: validation

Validate before calling

if (AuthDefaultSource.DINGTALK == source) {
    // no token endpoint: use login() only; skip refresh/revoke
    return dingtalkLogin(request, code);
}

Type guard

boolean hasAccessTokenEndpoint(AuthSource s) {
    try { s.accessToken(); return true; }
    catch (AuthException e) { return e.getErrcode() == AuthResponseStatus.UNSUPPORTED.getCode() ? false : true; }
}

Try / catch

catch (AuthException e) { if (e.getErrcode() == 5003) { /* DingTalk has no token endpoint; use login() flow */ } else throw e; }

Prevention

When it happens

Trigger: Calling AuthDingTalkRequest.getAccessToken(...) paths that invoke source.accessToken(), e.g. attempting a token refresh, revoke, or a generic flow that assumes every provider has a token endpoint; calling accessToken() manually on AuthDefaultSource.DINGTALK.

Common situations: Treating DingTalk like a standard OAuth2 provider in a generic multi-provider pipeline; calling refresh()/revoke() on a DingTalk request; new code paths added to AbstractAuthDingtalkRequest that assume a token URL exists.

Related errors


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