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"

Spring Security WebSessionOAuth2ServerAuthorizationRequestRepository assumes state parameter is url-decoded

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.