• TL;DR Java 9 HttpClient does not allow custom Authorization header unless you resort to a hack
    Read on:
    Over the weekend, we decided to add experimental support for Java 9 to our in-house apns-http2 library. The goal was to take away the OkHttp dependency + requirement for Jetty’s ALPN library (not that this combination is unstable).
    To my surprise, it’s impossible to set the “authorization” header! Well, it does support HTTP basic authentication, using a new callback method (which is quite a waste, more on that some other day). To authenticate with Apple’s push notification gateway (APNs endpoints) via HTTP/2, Apple’s documentation states that the “authorization” header be set to:
    bearer xxxxxxxx
    Setting it using HttpRequest.Builder doesn’t work:

    final HttpRequest.Builder rb = HttpRequest
        .newBuilder()
        .header("authorization", "bearer " + cachedJWTToken);
    

    On further investigation, it’s a forbidden header (after debugging the code right down). Internally, when headers are added via jdk.incubator.http.HttpRequest.Builder#header, they go to a map named userHeaders. When the request is built, authorization is stripped off, as it’s a forbidden user header.
    Fortunately, in the HttpRequestImpl class there’s a way to set system headers, which is where we ended up setting it. This is not a part of the public API, so we had to resort to reflection:

    Class reqClass = request.getClass();
    Method setHeaderMethod = reqClass.getDeclaredMethod("setSystemHeader", String.class, String.class);
    setHeaderMethod.setAccessible(true);
    setHeaderMethod.invoke(request, "authorization", "bearer " + cachedJWTToken);

    Now, with Java 9 and it’s new module system, we had to explicitly add the following VM option:
    –add-opens jdk.incubator.httpclient/jdk.incubator.http=com.clevertap.apns
    The above opens up the package jdk.incubator.http for reflection (otherwise setAccessible fails).
    And voilà! We could talk to APNs!
    We’ve already filed a bug for this with Oracle, as setting the authorization header as a user header must be allowed. It’s been acknowledged and can be found here. A little more information about this can also be found here.

    The Intelligent Mobile Marketing Platform

    See how today’s top brands use CleverTap to drive long-term growth and retention.

    Schedule a Demo Now!

    Last updated on January 30, 2025

    Author

    Jude Pereira LinkedIn

    Principal Architect at CleverTap, working on TesseractDB™. He also contributes to the engineering culture, improving developer productivity.

    Please enter a valid work email

    Smiling Woman Holding Phone