I spoke to Dropbox API support. They were very helpful and suggested a number of things:
This error indicates that the state value returned to your redirect
URI doesn't match the CSRF token that was stored in the session. The
state value on your sample redirect URI matches the state value given
to the /authorize URL though, so it looks like the issue is with the
value stored in the session. A few things come to mind that might
cause this:
- Are you calling WebAuth.start multiple times for a single app authorization flow? If so, it's possible you're storing the CSRF token
for one, but are browsing to the /authorize URL with the other.
- Is your session storage not working correctly? The Dropbox PHP SDK uses the csrfTokenStore you pass to the WebAuth constructor. If that
isn't able to store the new CSRF token, or is returning stale values,
that could cause this mismatch.
- Are you switching between different instances of your app, and so accessing different sessions?
It turned out to be the first theorized problem. An AJAX call happened in the background which had a login check that also redirected to the authorize page, thus creating multiple requests. Once I disabled this the problem was gone.