Describe the bug
The redirect url generated by the login endpoint url-encodes the query parameters:
OAuth2AuthorizationRequest:
// Encode query parameter value according to RFC 3986
private static String encodeQueryParam(String value) {
return UriUtils.encodeQueryParam(value, StandardCharsets.UTF_8);
}
As seen in the example, the state parameter is url-encoded (last symbol "=" has been encoded to "%3D"
WebSessionOAuth2ServerAuthorizationRequestRepository:
...and its stored in its raw version (not url encoded):
@Override
public Mono<Void> saveAuthorizationRequest(OAuth2AuthorizationRequest authorizationRequest,
ServerWebExchange exchange) {
Assert.notNull(authorizationRequest, "authorizationRequest cannot be null");
Assert.notNull(exchange, "exchange cannot be null");
// @formatter:off
return getSessionAttributes(exchange)
.doOnNext((sessionAttrs) -> {
Assert.hasText(authorizationRequest.getState(), "authorizationRequest.state cannot be empty");
sessionAttrs.put(this.sessionAttributeName, authorizationRequest);
})
.then();
// @formatter:on
}
...but its compared to the urlencoded value when removing:
@Override
public Mono<OAuth2AuthorizationRequest> removeAuthorizationRequest(ServerWebExchange exchange) {
String state = getStateParameter(exchange);
if (state == null) {
return Mono.empty();
}
// @formatter:off
return getSessionAttributes(exchange)
.filter((sessionAttrs) -> sessionAttrs.containsKey(this.sessionAttributeName))
.flatMap((sessionAttrs) -> {
OAuth2AuthorizationRequest authorizationRequest = (OAuth2AuthorizationRequest) sessionAttrs.get(this.sessionAttributeName);
if (state.equals(authorizationRequest.getState())) {
sessionAttrs.remove(this.sessionAttributeName);
return Mono.just(authorizationRequest);
}
return Mono.empty();
});
// @formatter:on
}
in my webflux project, this returns the url-encoded query parameter
private String getStateParameter(ServerWebExchange exchange) {
Assert.notNull(exchange, "exchange cannot be null");
return exchange.getRequest().getQueryParams().getFirst(OAuth2ParameterNames.STATE);
}
The end result is that the stored state (!url encoded) is compared to query parameter "state" on the authorization code callback, and a "AUTHORIZATION_REQUEST_NOT_FOUND_ERROR_CODE" is thrown.
Expected behavior:
The WebSessionOAuth2ServerAuthorizationRequestRepository should not assume that the ServerWebExchange "getQueryParameters" handles url decoding.
Comment From: mariusingjer
I disagree with myself, query parameter decoding is such a low level construct in the framework, valid assumption.