GitHub OAuth responses are urlencoded, not JSON
serain opened this issue · 2 comments
First of all, thanks for this. It looks really great and I'm hoping it can save me a lot of time.
I'm running into an issue trying to get OAuth flow working with GitHub. I'm getting a 500 on the callback. It looks like an issue with httpx_oauth client.get_access_token
INFO: 127.0.0.1:51913 - "GET /auth/github/callback?code=<MY_CODE>&state=<MY_STATE> HTTP/1.1" 500 Internal Server Error
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/Users/user/.local/share/virtualenvs/console-HZgljEfn/lib/python3.8/site-packages/uvicorn/protocols/http/httptools_impl.py", line 385, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "/Users/user/.local/share/virtualenvs/console-HZgljEfn/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
return await self.app(scope, receive, send)
File "/Users/user/.local/share/virtualenvs/console-HZgljEfn/lib/python3.8/site-packages/fastapi/applications.py", line 171, in __call__
await super().__call__(scope, receive, send)
File "/Users/user/.local/share/virtualenvs/console-HZgljEfn/lib/python3.8/site-packages/starlette/applications.py", line 102, in __call__
await self.middleware_stack(scope, receive, send)
File "/Users/user/.local/share/virtualenvs/console-HZgljEfn/lib/python3.8/site-packages/starlette/middleware/errors.py", line 181, in __call__
raise exc from None
File "/Users/user/.local/share/virtualenvs/console-HZgljEfn/lib/python3.8/site-packages/starlette/middleware/errors.py", line 159, in __call__
await self.app(scope, receive, _send)
File "/Users/user/.local/share/virtualenvs/console-HZgljEfn/lib/python3.8/site-packages/starlette/exceptions.py", line 82, in __call__
raise exc from None
File "/Users/user/.local/share/virtualenvs/console-HZgljEfn/lib/python3.8/site-packages/starlette/exceptions.py", line 71, in __call__
await self.app(scope, receive, sender)
File "/Users/user/.local/share/virtualenvs/console-HZgljEfn/lib/python3.8/site-packages/starlette/routing.py", line 550, in __call__
await route.handle(scope, receive, send)
File "/Users/user/.local/share/virtualenvs/console-HZgljEfn/lib/python3.8/site-packages/starlette/routing.py", line 227, in handle
await self.app(scope, receive, send)
File "/Users/user/.local/share/virtualenvs/console-HZgljEfn/lib/python3.8/site-packages/starlette/routing.py", line 41, in app
response = await func(request)
File "/Users/user/.local/share/virtualenvs/console-HZgljEfn/lib/python3.8/site-packages/fastapi/routing.py", line 186, in app
solved_result = await solve_dependencies(
File "/Users/user/.local/share/virtualenvs/console-HZgljEfn/lib/python3.8/site-packages/fastapi/dependencies/utils.py", line 537, in solve_dependencies
solved = await call(**sub_values)
File "/Users/user/.local/share/virtualenvs/console-HZgljEfn/lib/python3.8/site-packages/httpx_oauth/integrations/fastapi.py", line 40, in __call__
access_token = await self.client.get_access_token(code, redirect_url)
File "/Users/user/.local/share/virtualenvs/console-HZgljEfn/lib/python3.8/site-packages/httpx_oauth/oauth2.py", line 121, in get_access_token
data = cast(Dict[str, Any], response.json())
File "/Users/user/.local/share/virtualenvs/console-HZgljEfn/lib/python3.8/site-packages/httpx/_models.py", line 854, in json
return jsonlib.loads(self.text, **kwargs)
File "/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/__init__.py", line 357, in loads
return _default_decoder.decode(s)
File "/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)```
Diving into httpx_oauth
, it seems the issue is that GitHub is returning form-data instead of a json response:
b'access_token=<ACCESS_TOKEN>&scope=user%3Aemail&token_type=bearer'
so this line in oauth.py
is throwing a JSONDecodeError
:
data = cast(Dict[str, Any], response.json())
This can be fixed by adding the headers={"Accept": "application/json"}
headers when fetching the access token, as per https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/#web-application-flow
I then run into another problem down the line, as there's no expires_at
key in GitHub's response:
File "/Users/user/.local/share/virtualenvs/console-HZgljEfn/lib/python3.8/site-packages/fastapi_users/router/oauth.py", line 102, in callback
expires_at=token["expires_at"],
KeyError: 'expires_at'
Ok, I can reproduce the issue. It seems that GitHub is returning urlencoded responses instead of JSON (🙄). I'll transfer this issue to httpx-oauth
. Thank you for the feeback!