-1

I’m using AWS API Gateway HTTP API v2 with a Lambda function running a Java Spring Boot application
The integration type is Lambda proxy integration with payloadFormatVersion: 2.0.

Everything works fine, except that query parameters get modified by API Gateway before reaching my Spring Boot app.

The problem

When I call this endpoint:

GET https://api.example.com/welcome?param1=aGVsbG8gbXkgbmFtZSBpcyBqb2huCg==

What I see in logs

DEBUG --- Securing GET /welcome?param1=aGVsbG8gbXkgbmFtZSBpcyBqb2huCg==
DEBUG --- GET "/welcome?param1=aGVsbG8gbXkgbmFtZSBpcyBqb2huCg=="
INFO  --- preHandle: method=GET, uri=/welcome, parameters=[param1=aGVsbG8gbXkgbmFtZSBpcyBqb2huCg]

As you can see, the request arrives with the correct value (== present),
but by the time Spring handles it, the padding is missing.


What I tried

To work around this issue, I added a filter that attempts to automatically restore the missing Base64 padding when needed:

@Component
@Order(HIGHEST_PRECEDENCE)
public class Base64PaddingFixFilter extends OncePerRequestFilter {

  @Override
  protected void doFilterInternal(
      HttpServletRequest request,
      HttpServletResponse response,
      FilterChain filterChain)
      throws ServletException, IOException {

    var originalParams = request.getParameterMap();

    var fixedParams = originalParams.entrySet().stream()
        .collect(Collectors.toMap(
            Map.Entry::getKey,
            e -> Arrays.stream(e.getValue())
                       .map(Base64PaddingFixFilter::padBase64IfNeeded)
                       .toArray(String[]::new)));

    var hasModifiedParams = !fixedParams.equals(originalParams);

    if (hasModifiedParams) {
      var wrapped = new FixedParamsRequestWrapper(request, fixedParams);
      filterChain.doFilter(wrapped, response);
    } else {
      filterChain.doFilter(request, response);
    }
  }

  private static String padBase64IfNeeded(String s) {
    if (s == null) return null;
    var len = s.length();
    if (len == 0) return s;

    var base64UrlPattern = "^[A-Za-z0-9_\\-]+=*$";
    if (!s.matches(base64UrlPattern)) return s;

    var mod = len % 4;
    if (mod == 0) return s;
    var pad = 4 - mod;
    return s + "=".repeat(pad);
  }

  private static class FixedParamsRequestWrapper extends HttpServletRequestWrapper {
    private final Map<String, String[]> fixedParams;

    public FixedParamsRequestWrapper(HttpServletRequest request, Map<String, String[]> fixedParams) {
      super(request);
      this.fixedParams = fixedParams;
    }

    @Override public String getParameter(String name) {
      var values = fixedParams.get(name);
      return (values != null && values.length > 0) ? values[0] : null;
    }

    @Override public Map<String, String[]> getParameterMap() { return fixedParams; }
    @Override public String[] getParameterValues(String name) { return fixedParams.get(name); }
  }
}

This works for Base64 parameters — it detects and restores missing = characters.


The problem with this workaround

If a query parameter is not Base64, but happens to match the Base64 pattern ([A-Za-z0-9_-]+=*),
the filter incorrectly adds padding to it, treating it as a “corrupted” Base64 value.

Example:

GET /welcome?param1=abc

becomes:

param1=abc=

which is obviously not correct.

So this approach is unreliable unless all query parameters are guaranteed to be Base64-encoded.


Questions

  1. Why does API Gateway HTTP API v2 remove or alter the padding (=) in query parameters before invoking the Lambda?

  2. Is there a way to configure API Gateway to preserve query parameters exactly as sent (no decoding/re-encoding)?

  3. Is there a more reliable workaround than inspecting and re-padding parameters manually ?

2
  • 2
    What is calling your API? You are using values that mean something in a URL and have not properly encoded the values. It should look something more like: https://api.example.com/welcome?param1=aGVsbG8gbXkgbmFtZSBpcyBqb2huCg%3D%3D Commented Nov 9 at 23:08
  • I’m running into this issue with my OAuth provider, which redirects back to my app with the state parameter as a Base64 value that isn’t URL-encoded (e.g., aGVsbG8gbXkgbmFtZSBpcyBqb2huCg==). Because of that, AWS API Gateway can cut off or change the query parameters, so by the time they reach my Spring Boot backend, the state doesn’t match anymore and the OAuth2 flow breaks. One idea I have is to grab the raw request before it gets parsed and manually re-encode the state and other values, but I’m not sure if that’s even possible. Commented Nov 12 at 8:03

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.