This has been fixed and it wasn't nginx's issue at all!
We were using a nodejs framework which reads a header and responds with 303 or 302. This app was incorrectly reading the header. http2 implies headers will be in lowercase and this app was reading the header in mixed/title case.
The reason it completely missed me was because I tested by copying the request as a curl command from browser. First I sent it directly to the app and saw 303 response(because the headers were in mixed/title case) then I sent it through nginx and I got 302 because nginx was converting it to lower case.
In hindsight, I should've tried to find some debug logs for the nodejs framework, turn it on and check what it was getting and how it was responding to requests.