langgenius/dify · error · BadRequest
redirect_uri is invalid
Error message
redirect_uri is invalid
What it means
Flask BadRequest (HTTP 400) raised at oauth_server.py:163 in OAuthServerAppApi.post (POST /console/api/oauth/provider) when the payload.redirect_uri is not present in oauth_provider_app.redirect_uris. This is the standard OAuth 2.0 redirect_uri allow-list check performed before returning app metadata (icon/label/scope) to the client.
Source
Thrown at api/controllers/console/auth/oauth_server.py:163
return view(self, oauth_provider_app, account, *args, **kwargs)
return decorated
@console_ns.route("/oauth/provider")
class OAuthServerAppApi(Resource):
@setup_required
@console_ns.expect(console_ns.models[OAuthProviderRequest.__name__])
@console_ns.response(200, "Success", console_ns.models[OAuthProviderAppResponse.__name__])
@oauth_server_client_id_required
@model_validate(OAuthProviderRequest)
def post(self, payload: OAuthProviderRequest, oauth_provider_app: OAuthProviderApp):
redirect_uri = payload.redirect_uri
# check if redirect_uri is valid
if redirect_uri not in oauth_provider_app.redirect_uris:
raise BadRequest("redirect_uri is invalid")
return jsonable_encoder(
{
"app_icon": oauth_provider_app.app_icon,
"app_label": oauth_provider_app.app_label,
"scope": oauth_provider_app.scope,
}
)
@console_ns.route("/oauth/provider/authorize")
class OAuthServerUserAuthorizeApi(Resource):
@setup_required
@login_required
@account_initialization_required
@with_current_user
@console_ns.expect(console_ns.models[OAuthClientPayload.__name__])
@console_ns.response(200, "Success", console_ns.models[OAuthProviderAuthorizeResponse.__name__])View on GitHub (pinned to ef8544b173)
Solutions
- Register the exact redirect_uri (scheme, host, port, path, and trailing slash) in the OAuthProviderApp.redirect_uris list.
- Copy the redirect_uri from the registered list verbatim into the request rather than retyping it.
- If multiple environments are needed, register all of them rather than reusing one app across envs.
- Pre-validate the URI locally against the fetched allow-list before calling the endpoint.
Defensive patterns
Strategy: validation
Validate before calling
// Fetch the registered redirect_uris and ensure yours is in the list before calling.
const meta = await fetch('/console/api/oauth/provider', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({client_id: cid, redirect_uri: ru})}).then(r=>r.json());
if (!meta || meta.error) { throw new Error('redirect_uri not allowed'); } Type guard
function redirectUriAllowed(uri: string, allowed: string[]): boolean {
return allowed.includes(uri);
} Try / catch
try {
await getAppMetadata(cid, redirectUri);
} catch (e) {
if (/redirect_uri is invalid/i.test(e.message)) { registerRedirectUri(redirectUri); }
else throw e;
} Prevention
- Register every callback variant (http/https, trailing slash) you will use.
- Copy URIs from the registration rather than typing them.
- Avoid reusing one app across environments with different callbacks.
When it happens
Trigger: POST /console/api/oauth/provider with a valid client_id and a redirect_uri that is not in the registered allow-list for that OAuthProviderApp. The exact-match membership test `redirect_uri not in oauth_provider_app.redirect_uris` fails.
Common situations: Client changed its callback URL (e.g. localhost -> production domain) without updating the app registration; trailing slash mismatch; http vs https mismatch; or a completely wrong callback entered.
Related errors
AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12).
Data as JSON: /api/errors/b813e071eaddf118.
Report an issue: GitHub.