-
Notifications
You must be signed in to change notification settings - Fork 819
Description
Bug Description
Clicking the Authorize button on the authorization.html webform does nothing. This when django-csp is an installed app and the CSP form-action directive is set to 'self' only. This has been observed in Chromium browsers, but does not occur in Firefox. Safari is untested.
To Reproduce
- Install the
django-csppackage in your django project as shown in their documentation. - Set the CSP directive
form-action: 'self'in the settings, per their documentation. Bothdjango-cspversions 3.x and 4.x have this issue but the setting is done differently insettings.py. - Create an Application, Confidential, Authorization Code, and at least one valid redirect URI.
- In a Chromium-based browser, attempt to complete the Authorization Code flow, coming from that external application/website.
- Django will serve the standard authorization.html template.
- Clicking the Authorize button will do nothing and the user will not be redirected to the Application's redirect_uri.
- Open the devtools and observe the error in the console. It should say that it refused to submit the form to the current location as it violates the Content Securty Policy form-action 'self' directive.
Error:
Refused to send form data to '{current location /o/authorize including query params}'
because it violates the following Content Security Policy directive: "form-action 'self'"
Expected behavior
User would normally be redirected back to external redirect URI with temporary authorization code.
Version
A Chromium version introduced in early 2025. django-oauth-toolkit versions 2.3.0 and 3.1.0.
- I have tested with the latest published release and it's still a problem.
- I have tested with the master branch and it's still a problem.
Additional context
My troubleshooting and workaround:
Since the webform in the authorization.html does not have the action attribute set, it defaults to the current window location. I found this to actually be a misleading console error as the form was indeed posting to the django server, which responds with 302 redirect to the redirect_uri. Chrome prevents the redirect, as observed in the Network tab of devtools, while the error message says it refused to POST the webform to the current window location.
I have implemented a workaround by overriding AuthorizationView.get to manually add the Application.redirect_uris to the form-action directive in the CSP header when serving the webform. Chromium now sees those as acceptable locations to submit the form, and allows the redirect. This way I can keep the global CSP form-action setting of 'self' while allowing it in this case. I am not permitted by my organization to change the global CSP settings, hence the view-specific CSP header change. My workaround is django-csp specific since it uses their API to alter CSP settings when the response goes through their middleware layer.
Snippet of my solution:
class AuthorizationViewOverride(AuthorizationView):
def get(self, request, *args, **kwargs):
response = super().get(request, *args, **kwargs)
... # get application redirect URIs and current CSP from settings
csp_form_action.extend(redirect_uris)
response._csp_replace = {"form-action": csp_form_action}
return response
Has anyone other than me observed this behavior, and has there been any discussion around it?