-
-
Notifications
You must be signed in to change notification settings - Fork 521
Description
Describe the bug
When Django receives requests without https, and not on http://localhost, and when we call get_consent_grant() it's expected to fail (unless AUTHLIB_INSECURE_TRANSPORT=true).
The problem is, instead of InsecureTransportError being propagated, an error 'Request' object has no attribute 'payload' is raised.
To Reproduce
Follow the documentation to setup OAuth2 server in Django.
The relevant part is this:
def authorize(request):
try:
grant = server.get_consent_grant(request, end_user=request.user)
except OAuth2Error as error:
return server.handle_error_response(request, error) # 👀 expect to end up here, but noRun the server on port 8008:
python manage.py runserver 8008Call the authorize route on http://localhost:8008, it works ✔️
curl --location 'http://localhost:8008/v1/oauth2/authorize/8ce87789-b5cd-44dc-aff3-af95497b46f6?response_type=code&client_id=myclientid&code_challenge=wgw5CZck78w8i9KtMWLRt7hwPTAeXghvXo602q8y9FY&redirect_uri=myapp%3A%2F%2Foauth2&code_challenge_method=S256'Now, add an entry in /etc/hosts to test:
127.0.0.1 mytestserver
Call the authorize route using http://mytestserver:8000. It fails. This is expected, but the error message isn't expected ❌
curl --location 'http://mytestserver:8008/v1/oauth2/authorize/8ce87789-b5cd-44dc-aff3-af95497b46f6?response_type=code&client_id=myclientid&code_challenge=wgw5CZck78w8i9KtMWLRt7hwPTAeXghvXo602q8y9FZ&redirect_uri=myapp%3A%2F%2Foauth2&code_challenge_method=S256'The error insecure_transport: OAuth 2 MUST utilize https. is expected, but the error that is actually raised in the end is 'Request' object has no attribute 'payload'
Error Stacks
{"code":"UNDEFINED_ERROR","message":"Undefined Error.","debug":"'Request' object has no attribute 'payload': Traceback (most recent call last):
File \"/home/carmen/.pyenv/versions/auth/lib/python3.10/site-packages/authlib/oauth2/rfc6749/authorization_server.py\", line 255, in get_consent_grant
request = self.create_oauth2_request(request)
File \"/home/carmen/.pyenv/versions/auth/lib/python3.10/site-packages/authlib/integrations/django_oauth2/authorization_server.py\", line 58, in create_oauth2_request
return DjangoOAuth2Request(request)
File \"/home/carmen/.pyenv/versions/auth/lib/python3.10/site-packages/authlib/integrations/django_oauth2/requests.py\", line 36, in __init__
super().__init__(request.method, request.build_absolute_uri(), request.headers)
File \"/home/carmen/.pyenv/versions/auth/lib/python3.10/site-packages/authlib/oauth2/rfc6749/requests.py\", line 69, in __init__
InsecureTransportError.check(uri)
File \"/home/carmen/.pyenv/versions/auth/lib/python3.10/site-packages/authlib/oauth2/rfc6749/errors.py\", line 65, in check
raise cls()
authlib.oauth2.rfc6749.errors.InsecureTransportError: insecure_transport: OAuth 2 MUST utilize https.
Expected behavior
InsecureTransportError should be raised, not a python error about accessing an attribute which doesn't exist.
Environment:
- OS: Ubuntu 24.04
- Python Version: 3.10
- Authlib Version: 1.6.1
Additional context
this is the path through the code:
OAuth2AuthorizeView.get()- -->
AuthorizationServer.get_consent_grant()- -->
AuthorizationServer.create_oauth2_request()- -->
DjangoOAuth2Request.__init__()- -->
OAuth2Request.__init__()- -->
InsecureTransportError.check()- -->
is_secure_transport(): Check here, returns false - raise
InsecureTransportError
- -->
- -->
- -->
- -->
- -->
- catch
OAuth2Error(InsecureTransportErroris anOAuth2Error
- -->
The Authlib code that catches this security exception does this:
except OAuth2Error as error:
# REQUIRED if a "state" parameter was present in the client
# authorization request. The exact value received from the
# client.
error.state = request.payload.state
raiseOne problem, is that it attempts to access request.payload. However, payload hasn't been set yet. It would be set only after passing this initial security check, in the OAuth2Request initializer.