{"record":{"id":"1336bee7974d4019","repo":"justauth/JustAuth","slug":"error","errorCode":null,"errorMessage":"${error}","messagePattern":"\\$\\{error\\}","errorType":"exception","errorClass":"AuthException","httpStatus":null,"severity":"error","filePath":"src/main/java/me/zhyd/oauth/request/AuthAppleRequest.java","lineNumber":55,"sourceCode":"        super(config, AuthDefaultSource.APPLE);\n    }\n\n    public AuthAppleRequest(AuthConfig config, AuthStateCache authStateCache) {\n        super(config, AuthDefaultSource.APPLE, authStateCache);\n    }\n\n    @Override\n    public String authorize(String state) {\n        return UrlBuilder.fromBaseUrl(super.authorize(state))\n            .queryParam(\"response_mode\", \"form_post\")\n            .queryParam(\"scope\", this.getScopes(\" \", false, AuthScopeUtils.getDefaultScopes(AuthAppleScope.values())))\n            .build();\n    }\n\n    @Override\n    public AuthToken getAccessToken(AuthCallback authCallback) {\n        if (!StringUtils.isEmpty(authCallback.getError())) {\n            throw new AuthException(authCallback.getError());\n        }\n        this.config.setClientSecret(this.getToken());\n        // if failed will throw AuthException\n        String response = doPostAuthorizationCode(authCallback.getCode());\n        JSONObject accessTokenObject = JSONObject.parseObject(response);\n        // https://developer.apple.com/documentation/sign_in_with_apple/tokenresponse\n        AuthToken.AuthTokenBuilder builder = AuthToken.builder()\n            .accessToken(accessTokenObject.getString(\"access_token\"))\n            .expireIn(accessTokenObject.getIntValue(\"expires_in\"))\n            .refreshToken(accessTokenObject.getString(\"refresh_token\"))\n            .tokenType(accessTokenObject.getString(\"token_type\"))\n            .idToken(accessTokenObject.getString(\"id_token\"));\n        if (!StringUtils.isEmpty(authCallback.getUser())) {\n            try {\n                AppleUserInfo userInfo = JSONObject.parseObject(authCallback.getUser(), AppleUserInfo.class);\n                builder.username(userInfo.getName().getFirstName() + \" \" + userInfo.getName().getLastName());\n            } catch (Exception ignored) {\n            }","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/justauth/JustAuth/blob/694bbf1b010d93404e3bfb4824d90e9ddfaebebb/src/main/java/me/zhyd/oauth/request/AuthAppleRequest.java#L37-L73","documentation":"AuthException thrown at the very top of AuthAppleRequest.getAccessToken when authCallback.getError() is non-empty. Apple's form_post response includes an error field (plus error_description) when Sign in with Apple fails, and JustAuth surfaces the error string directly as the message.","triggerScenarios":"Apple posting back an error such as user_cancelled_authorize, invalid_request, or unauthorized_client in the form body. Because response_mode=form_post (set in authorize()), the callback arrives as an HTTP POST form — a GET handler will see an empty callback and may mishandle it first.","commonSituations":"User tapped 'Cancel' on the Apple consent sheet; the web auth session expired before completion; the callback endpoint only accepts GET so the POST form fields are never bound to AuthCallback; private-email relay issues causing error_description on return.","solutions":["Handle POST on the callback endpoint (Apple posts via form_post) and bind form fields error/error_description/code/user into AuthCallback","If error is user_cancelled_authorize, treat it as a benign cancellation rather than a server fault","Log error_description alongside error for the real reason","Ensure your developer account's Services ID and return URL are configured for Sign in with Apple"],"exampleFix":"// before\n@PostMapping(\"/callback/apple\")\npublic Object callback(@RequestParam Map<String,?> params) { ... }\n\n// after — explicitly surface Apple's error before triggering the flow\nAuthCallback cb = AuthCallback.of(); // bind error, error_description, code, user from the form POST\nif (StringUtils.isNotEmpty(cb.getError())) {\n    // user cancelled or Apple rejected — respond 200 with a friendly message\n    return redirect(\"/login?cancelled=true\");\n}\nreturn authRequest.login(cb);","handlingStrategy":"validation","validationCode":"// Apple posts the callback via form_post — read form fields and check error first\nAuthCallback cb = AuthCallback.of(); // bind error/error_description/code/user from the POST body\nif (StringUtils.isNotEmpty(cb.getError())) {\n    boolean cancelled = \"user_cancelled_authorize\".equals(cb.getError());\n    return cancelled ? redirect(\"/login?cancelled=true\") : redirect(\"/login?error=\" + cb.getError());\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Accept POST on the Apple callback route (response_mode=form_post)","Treat user_cancelled_authorize as a normal exit, not an exception path","Configure the Services ID return URL exactly as the redirectUri"],"tags":["apple","oauth","form-post","callback"],"backgroundTag":null,"analyzedSha":"694bbf1b010d93404e3bfb4824d90e9ddfaebebb","analyzedAt":"2026-08-14T15:16:59.945Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}