{"record":{"id":"f31f3f312f280fbf","repo":"langgenius/dify","slug":"refresh-token-is-required","errorCode":null,"errorMessage":"refresh_token is required","messagePattern":"refresh_token is required","errorType":"http","errorClass":"BadRequest","httpStatus":400,"severity":"error","filePath":"api/controllers/console/auth/oauth_server.py","lineNumber":229,"sourceCode":"                    raise BadRequest(\"client_secret is invalid\")\n\n                if payload.redirect_uri not in oauth_provider_app.redirect_uris:\n                    raise BadRequest(\"redirect_uri is invalid\")\n\n                access_token, refresh_token = OAuthServerService.sign_oauth_access_token(\n                    grant_type, code=payload.code, client_id=oauth_provider_app.client_id\n                )\n                return jsonable_encoder(\n                    {\n                        \"access_token\": access_token,\n                        \"token_type\": \"Bearer\",\n                        \"expires_in\": OAUTH_ACCESS_TOKEN_EXPIRES_IN,\n                        \"refresh_token\": refresh_token,\n                    }\n                )\n            case OAuthGrantType.REFRESH_TOKEN:\n                if not payload.refresh_token:\n                    raise BadRequest(\"refresh_token is required\")\n\n                access_token, refresh_token = OAuthServerService.sign_oauth_access_token(\n                    grant_type, refresh_token=payload.refresh_token, client_id=oauth_provider_app.client_id\n                )\n                return jsonable_encoder(\n                    {\n                        \"access_token\": access_token,\n                        \"token_type\": \"Bearer\",\n                        \"expires_in\": OAUTH_ACCESS_TOKEN_EXPIRES_IN,\n                        \"refresh_token\": refresh_token,\n                    }\n                )\n\n\n@console_ns.route(\"/oauth/provider/account\")\nclass OAuthServerUserAccountApi(Resource):\n    @setup_required\n    @console_ns.expect(console_ns.models[OAuthClientPayload.__name__])","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/auth/oauth_server.py#L211-L247","documentation":"Flask BadRequest (HTTP 400) at oauth_server.py:229 in the REFRESH_TOKEN branch of the token endpoint. grant_type=refresh_token was accepted but payload.refresh_token is empty/None, so there is nothing to rotate. The service call OAuthServerService.sign_oauth_access_token is never reached.","triggerScenarios":"POST /oauth/provider/token with grant_type=refresh_token and a missing or empty refresh_token field. Usually a client that did not persist the refresh_token from the prior authorization_code exchange.","commonSituations":"Client lost the refresh_token (storage cleared, cookie expired, process restart without persistence) and attempts a refresh anyway; or the field name was mistyped in the JSON body.","solutions":["Persist the refresh_token returned from the authorization_code exchange and pass it verbatim in the refresh request.","If the refresh_token is genuinely lost, restart the flow at /oauth/provider/authorize to obtain a fresh code -> token pair.","Validate the JSON body field name is exactly 'refresh_token' before sending."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (grantType === 'refresh_token' && !refreshToken) {\n  throw new Error('No refresh_token stored — re-authorize from scratch');\n}","typeGuard":"function hasRefreshToken(t: unknown): t is string { return typeof t === 'string' && t.length > 0; }","tryCatchPattern":"try {\n  await token({grant_type:'refresh_token', refresh_token: refreshToken});\n} catch (e) {\n  if (/refresh_token is required/i.test(e.message)) { restartOAuthFlow(); } else throw e;\n}","preventionTips":["Persist refresh_token durably (not just in memory) after the code exchange.","Send the field name exactly as 'refresh_token'.","Re-authorize when the token is irrecoverably lost."],"tags":["oauth-server","refresh-token","token","validation"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}