{"record":{"id":"9a50ab2d4d43392f","repo":"justauth/JustAuth","slug":"submsg","errorCode":null,"errorMessage":"${subMsg}","messagePattern":"\\$\\{subMsg\\}","errorType":"exception","errorClass":"AuthException","httpStatus":null,"severity":"error","filePath":"src/main/java/me/zhyd/oauth/request/AuthAlipayCertRequest.java","lineNumber":63,"sourceCode":"    protected void checkCode(AuthCallback authCallback) {\n        if (StringUtils.isEmpty(authCallback.getAuth_code())) {\n            throw new AuthException(AuthResponseStatus.ILLEGAL_CODE, source);\n        }\n    }\n\n    @Override\n    public AuthToken getAccessToken(AuthCallback authCallback) {\n        AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();\n        request.setGrantType(\"authorization_code\");\n        request.setCode(authCallback.getAuth_code());\n        AlipaySystemOauthTokenResponse response;\n        try {\n            response = this.alipayClient.certificateExecute(request);\n        } catch (Exception e) {\n            throw new AuthException(e);\n        }\n        if (!response.isSuccess()) {\n            throw new AuthException(response.getSubMsg());\n        }\n        return AuthToken.builder()\n            .accessToken(response.getAccessToken())\n            .uid(response.getUserId())\n            .expireIn(Integer.parseInt(response.getExpiresIn()))\n            .refreshToken(response.getRefreshToken())\n            .build();\n    }\n\n\n    /**\n     * 刷新access token （续期）\n     *\n     * @param authToken 登录成功后返回的Token信息\n     * @return AuthResponse\n     */\n    @Override\n    public AuthResponse<AuthToken> refresh(AuthToken authToken) {","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/justauth/JustAuth/blob/694bbf1b010d93404e3bfb4824d90e9ddfaebebb/src/main/java/me/zhyd/oauth/request/AuthAlipayCertRequest.java#L45-L81","documentation":"After certificateExecute returns, AuthAlipayCertRequest.getAccessToken checks response.isSuccess(); on failure it throws AuthException with the response's subMsg — Alipay's own business-error description (e.g. invalid code, wrong grant type, app not authorized for the oauth API). This is a rejected token exchange, i.e. Alipay processed the request and said no.","triggerScenarios":"Exchanging an auth_code that was already used or expired; the app lacks the 获取会员信息 (user info) capability or is_au not enabled so AlipaySystemOauthTokenRequest is refused; app_id mismatch between the code's app and the configured app; refresh-style grant on a code grant request.","commonSituations":"User refreshes the callback URL causing code reuse; Alipay app not signed/approved for the oauth scope in production while it worked in sandbox; wrong appId in AuthConfig relative to the app that issued the code.","solutions":["Read subMsg literally (e.g. '无效的授权码' = auth_code invalid/consumed) and match to the fix: re-authorize the user instead of reusing the code.","Confirm the Alipay open-platform app has the user-info product signed and the gateway environment (sandbox/prod) matches the credentials.","Ensure AuthConfig.clientId equals the appId that generated the auth_code.","Process the callback exactly once; make the token exchange idempotent by storing the resulting token keyed on code."],"exampleFix":"// before\n// user re-opens the callback URL -> same auth_code exchanged twice -> subMsg exception\n\n// after\n// idempotent callback: key on auth_code\nAuthToken cached = tokenStore.byCode(cb.getAuth_code());\nif (cached != null) return ok(cached);\nAuthToken t = request.getAccessToken(cb); tokenStore.save(cb.getAuth_code(), t); return ok(t);","handlingStrategy":"try-catch","validationCode":"// idempotency guard: never exchange the same auth_code twice\nif (tokenStore.find(cb.getAuth_code()) != null) { return ok(tokenStore.find(cb.getAuth_code())); }","typeGuard":null,"tryCatchPattern":"try { return request.getAccessToken(cb); } catch (AuthException e) { log.warn(\"Alipay rejected token exchange: {}\", e.getMessage()); return restartAlipayAuthorize(); }","preventionTips":["Make the auth_code exchange idempotent by caching results keyed on the code.","Confirm the Alipay app has the oauth/user-info product enabled and environment matches (sandbox vs prod).","Ensure AuthConfig.clientId equals the appId that issued the code.","Do not auto-retry business rejections — send the user back to authorize."],"tags":["justauth","alipay","business-error","expired-code","external-api"],"backgroundTag":null,"analyzedSha":"694bbf1b010d93404e3bfb4824d90e9ddfaebebb","analyzedAt":"2026-08-14T15:16:59.945Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}