ASVS 5.0 V10.4.12 (Level 3) says the authorization server must allow only the response_mode value that a given client needs. You can do that by validating the parameter against expected values, or by using pushed authorization requests (PAR) or JWT-secured authorization requests (JAR), where the value is fixed before the browser is involved.
Why it matters
The response mode decides how the authorization response reaches the client: in the query string, in the fragment, or through a form post. An attacker who can change it might push a code into a fragment or a page that leaks it. Fixing the mode per client closes that option.
How to implement it
Store allowed modes in the client registration and check them on every authorization request.
def check_response_mode(client, params):
mode = params.get("response_mode", client.default_response_mode)
if mode not in client.allowed_response_modes:
raise InvalidRequest("response_mode not allowed")
return mode
With PAR, the client sends the parameters directly to the server over an authenticated call, and the browser carries only a request URI. That removes the chance to tamper with the value.
How to test it
Start a flow with a response_mode the client is not registered for, such as fragment for a server side app. Expect an error. Repeat with the registered value and confirm success.
A note on fragment responses
Fragment delivery places the response in the part of the URL after the hash, where server logs do not see it but scripts on the page do. Form post delivery sends it in a request body to the client. Each has uses, so the right answer is per client. A server side app usually needs only the query mode for the code flow, and nothing else. Writing that down in the registration is what this requirement is checking.
Common mistakes
- Trusting the parameter because the redirect URI is already checked.
- Allowing every mode globally "for compatibility".
Quick check
Name two ways to meet this requirement.
Validate the value against a per-client allow list, or use PAR or JAR so the value is protected from tampering.