Hi Jonas, On Tue, Nov 25, 2025 at 10:03 PM Primbs, Jonas < [email protected]> wrote:
> > Do we all agree that the specific scenario where authorization codes > leak through near real-time access to access logs can be mitigated by > always exchanging the authorization code, even when CSRF is suspected? > (absence of or non-matching state; assuming a conformant AS/IdP that has > single-use authorization codes) > > Yes. I recommend to enforce PKCE in addition and using an authorization > code which inavlidates the authorization code if no matching code verifier > is provided in the token request. Otherwise the authorization code will not > only be invalidated at the AS/IdP, but also resolved for an unwanted > access/refresh/ID token. Depends on the application whether this is an > issue. It’s important, that the client does not use these tokens, otherwise > you have a CSRF attack. > Yes, this is in the AS/IdP's hands though, nothing a client could do here. > Keep in mind, that in the logging scenario, in theory, the attacker may > resolve the authorization code before the client does. I think in practice > this is unrealistic but it may depend on the client implementation. > Yes, I'll try to add a test for that but it indeed looks like an unrealistic scenario, and also more something that's in the hands of the AS/IdP (here, the attacker would successfully exchange the authorization code against tokens, but then when the victim in turn tries to exchange the authorization code, the AS/IdP would revoke the tokens, right? From the client's pov there would be a successful token request for the attacker, then an invalid_grant for the victim; and the access token for the attacker's session would be revoked so requests to protected resources would fail; in an OIDC context, I would expect that the attacker's session be invalidated through the backchannel logout endpoint, but it depends whether the client and IdP support it, and possibly how th IdP implements authorization code reuse). > > And the other scenarios (brought in another thread) where the > authorization code leaks through a downgrade to response_mode=fragment, or > the victim sharing the URL (with authorization code) following an error, > can be mitigated by always redirecting, even (particularly) in case of > errors, to remove any code from the URL? (I chose to redirect to the same > callback endpoint but with an error=, using a custom error value for cases > like missing input –likely a response_mode=fragment downgrade– or missing > session state –i.e. no cookies–, and always including a hash in the > redirect URL –I use the same error=– to remove any authorization code from > a response_mode=fragment downgrade) > > Yes, but keep in mind that if no specific response_mode can be enforced by > the AS/IdP, this response_mode mutation may happen independently from the > client’s expected response mode. > For example, if your client expects response_mode=query or > response_mode=form_post, the attacker may choose > response_mode=fragment.This results in the browser being redirected to the > client with authorization code as fragment parameter, e.g., > https://client.example.com/callback#code=a&state=b. > The client backend will expect a POST request to /callback in case of > response_mode=form_post or a GET request with query parameters in case of > response_mode=query. > Assuming the client developer has sufficiently implemented the GET > endpoint in both cases which redirects the user’s browser to > /callback?error=missing_parameters, the browser’s URL bar will still > display the fragment parameters, e.g., > https://client.example.com/callback?error=missing_parameters#code=a&state=b. > I was also surprised that the browser persists the fragment part of the URL > on redirects, but historically it makes sense. > Therefore, I recommend to append an empty fragment part (#) to the end of > the redirect URL, e.g., redirecting to /callback?error=missing_parameters# > because only this will also clear the authorization code from the browser’s > URL. > Yes, as I said (though using the term hash rather than fragment), I always include a fragment in the redirect in this case. I chose to duplicate the error in the fragment rather than using an empty fragment (just in case an empty fragment is not enough), so I redirect to /callback?error=missing_parameters#error=missing_parameters > > Keycloak can do that using Client Policies for instance. > > Interesting, I haven’t seen there is a client policy which enforces > specific response modes. Can you share this? I would be interested for my > customers too. > That's right, Keycloak can only enforce PKCE and response types (and some other best practices), not response modes. I started a discussion there suggesting that idea: https://github.com/keycloak/keycloak/discussions/44495 -- Thomas Broyer /tɔ.ma.bʁwa.je/ <https://ipa-reader.com/?text=t%C9%94.ma.b%CA%81wa.je&voice=Mathieu>
_______________________________________________ OAuth mailing list -- [email protected] To unsubscribe send an email to [email protected]
