It is said here that if the request failed, it will return error with HTTP status code 400 but I'm getting HTTP status code 200 even when it is returning an error.
I'm hitting https://stackoverflow.com/oauth/access_token/json
This request is responded to with either an error (HTTP status code 400) or an access token of the form access_token=...&expires=1234. expires will only be set if scope does not include no_expiry, the use of which is strongly advised against unless your app truly needs perpetual access.
In order to get access_token and expires (if applicable) wrapped in a JSON object, POST to https://stackoverflow.com/oauth/access_token/json instead.