How to use a custom HTTP client

The OAuth 2.0 / OpenID Connect SDK sends HTTP requests using Java's included java.net.HttpURLConnection class.

To use a another HTTP client, for example Apache's HttpClient, implement the HTTPRequestSender interface. Whenever you have client code that needs to make HTTP request, for instance to call the token endpoint of an OAuth 2.0 server, pass your custom HTTP client to the send method of the HTTP request.

Example token request using a custom HTTP client:

// Your custom HTTP client implementing the HTTPRequestSender interface
HTTPRequestSender myHttpClient = new ApacheHttpClient();

// Make a token request and use the custom HTTP client to send it
TokenRequest tokenRequest = new TokenRequest(...);
HTTPResponse httpResponse = tokenRequest.toHTTPRequest().send(myHttpClient);

// Continue as usual
TokenResponse tokenResponse = TokenResponse.parse(httpResponse);

The HTTPRequestSender interface was introduced in v11.0 of the SDK.

Here is an example working HTTPRequestSender based on the v4.5 Apache HTTP client:

import com.nimbusds.oauth2.sdk.http.*;
import com.nimbusds.oauth2.sdk.util.*;
import net.jcip.annotations.*;
import org.apache.http.*;
import org.apache.http.client.methods.*;
import org.apache.http.entity.*;
import org.apache.http.impl.client.*;
import org.apache.http.util.*;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * Apache HTTP client (v4.5) for handling {@code HTTPRequest.send()} calls in
 * the SDK.
 */
@ThreadSafe
public static class ApacheHttpClient implements HTTPRequestSender {

    private final CloseableHttpClient httpclient = HttpClients.createDefault();

        @Override
        public ReadOnlyHTTPResponse send(final ReadOnlyHTTPRequest httpRequest)
            throws IOException {

            RequestBuilder builder;
            switch (httpRequest.getMethod()) {
                case GET:
                        builder = RequestBuilder.get();
                        break;
                case POST:
                        builder = RequestBuilder.post();
                        break;
                case PUT:
                        builder = RequestBuilder.put();
                        break;
                case DELETE:
                        builder = RequestBuilder.delete();
                        break;
                default:
                        throw new IOException("Unsupported HTTP method: " +
                            httpRequest.getMethod());
            }
            builder.setUri(httpRequest.getURI());

            for (Map.Entry<String, List<String>> en: httpRequest.getHeaderMap().entrySet()) {
                String headerName = en.getKey();
                List<String> headerValues = en.getValue();
                if (CollectionUtils.isEmpty(headerValues)) {
                    continue; // no header values, skip header
                }
                for (String headerValue: headerValues) {
                    builder.setHeader(headerName, headerValue);
                }
            }

            if (httpRequest.getBody() != null) {
                BasicHttpEntity entity = new BasicHttpEntity();
                entity.setContent(
                    new ByteArrayInputStream(
                        httpRequest.getBody().getBytes(StandardCharsets.UTF_8)
                        )
                    );
                builder.setEntity(entity);
            }

            HttpUriRequest request = builder.build();

            CloseableHttpResponse response = httpclient.execute(request);

            StatusLine statusLine = response.getStatusLine();

            HTTPResponse httpResponse = new HTTPResponse(statusLine.getStatusCode());
            httpResponse.setStatusMessage(statusLine.getReasonPhrase());

            for (Header header: response.getAllHeaders()) {
                httpResponse.setHeader(header.getName(), header.getValue());
            }

            HttpEntity httpEntity = response.getEntity();
            if (httpEntity != null) {
                String body = EntityUtils.toString(httpEntity);
                if (StringUtils.isNotBlank(body)) {
                     httpResponse.setBody(body);
                }
            }
            return httpResponse;
        }
}
}

The example ApacheHttpClient client has the following dependency:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.14</version>
</dependency>