What the message looks like
Error 400: redirect_uri_mismatchCommon causes
- http instead of https because the app behind a TLS proxy misdetects its own scheme.
- Trailing slash,
index.phpin the path or a different port. - Different hostname than registered, e.g. an internal address or www vs. no www.
- New callback URL after an app update while the IdP still has the old one.
- Wrong client: the client ID belongs to another environment (test/production).
Check
- Get the authorize URL that is sent (Nextcloud user_oidc, provider ID 1)
curl -s -o /dev/null -w '%{redirect_url}\n' https://cloud.example.com/apps/user_oidc/login/1 - Decode redirect_uri from the authorize URL
python3 -c "import sys,urllib.parse as u;print(u.parse_qs(u.urlparse(sys.argv[1]).query)['redirect_uri'][0])" 'PASTE_AUTHORIZE_URL' - Show the Nextcloud proxy settings
sudo -u www-data php /var/www/nextcloud/occ config:system:get overwriteprotocol; sudo -u www-data php /var/www/nextcloud/occ config:system:get overwrite.cli.url
Fix
- Compare the decoded redirect_uri character by character with the IdP registration.
- Behind a TLS proxy set
'overwriteprotocol' => 'https'so the app builds https URLs. - For Nextcloud user_oidc register
https://cloud.example.com/apps/user_oidc/code, with'htaccess.RewriteBase' => '/'so there is no index.php. - No wildcards in production – register exact URLs.
- In Entra ID the error is AADSTS50011, in Keycloak “Invalid parameter: redirect_uri” – the fix is the same.
FAQ
Why does it work internally but not from outside?
Internally the app builds a URL with an internal hostname or http, but the external https address is registered. The overwrite settings fix that.
Does a trailing slash really matter?
Yes. Most IdPs compare the redirect_uri as an exact string. /code and /code/ are two different URLs.