title: JWT Bearer Token Authentication with Apache Camel AHC-WS Websocket Component
body: <h3>Context</h3>
  
  <p>We are currently setting up a Springboot project using Apache Camel as the integration framework.</p>
  
  <p>At the end of our route we need to send messages with the WSS websocket protocol, where our application acts as the client and needs to send the messages to a remote server which exposes a websocket endpoint.</p>
  
  <p>But the remote server first requires an authentication during the WSS handshake. In fact it requires some specific HTTP headers including the <code>Authorization: Bearer {jwt-bearer-token}</code> header. The token is only required during the handshake. After the websocket has been opened no further authentication is needed anymore.</p>
  
  <h3>Approach</h3>
  
  <p>Since it seems to be the only websocket client component for Apache Camel, we intended to use the <a href="https://github.com/apache/camel/blob/master/components/camel-ahc-ws/src/main/docs/ahc-ws-component.adoc" rel="nofollow noreferrer">AHC-WS component</a> as shown in the <code>POM</code> below:</p>
  
  <pre class="lang-xml prettyprint-override"><code>...
  
  &lt;dependency&gt;
      &lt;groupId&gt;org.apache.camel&lt;/groupId&gt;
      &lt;artifactId&gt;camel-spring-boot-starter&lt;/artifactId&gt;
      &lt;version&gt;3.0.0-M2&lt;/version&gt;
  &lt;/dependency&gt;
  &lt;dependency&gt;
      &lt;groupId&gt;org.apache.camel&lt;/groupId&gt;
      &lt;artifactId&gt;camel-ahc-ws&lt;/artifactId&gt;
      &lt;version&gt;3.0.0-M2&lt;/version&gt;
  &lt;/dependency&gt;
  
  ...
  </code></pre>
  
  <p>In our route definition we then append the required headers to the message (e.g. the <code>Authorization</code> header with the JWT bearer token). Additionally we log the token to see if it really gets added as a header of the message (which it is).</p>
  
  <pre class="lang-xml prettyprint-override"><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;routes xmlns="http://camel.apache.org/schema/spring"&gt;
      &lt;route id="distributorRoute"&gt;
          &lt;from uri="seda:distributorEntryPoint"/&gt;
          &lt;setHeader headerName="Authorization"&gt;
              &lt;simple&gt;Bearer {jwt-bearer-token}&lt;/simple&gt;
          &lt;/setHeader&gt;
          &lt;log message="${header.Authorization}"/&gt;
          &lt;to uri="ahc-wss://{remote-server-wss-endpoint}&gt;
      &lt;/route&gt;
  &lt;/routes&gt;
  </code></pre>
  
  <h3>Problem</h3>
  
  <p>Simply said, the messages cannot be sent via WSS and it seems like the connection is never established.</p>
  
  <p>The application produces the following NPE exception:</p>
  
  <pre><code>2019-06-07 15:52:00.304  INFO 17164 --- [butorEntryPoint] o.a.camel.component.ahc.ws.WsEndpoint    : Reconnecting websocket: wss://{remote-server-wss-endpoint}
  
  ...
  
  java.lang.NullPointerException: null
      at org.apache.camel.component.ahc.ws.WsProducer.sendMessage(WsProducer.java:76) ~[camel-ahc-ws-3.0.0-M2.jar:3.0.0-M2]
      at org.apache.camel.component.ahc.ws.WsProducer.process(WsProducer.java:51) ~[camel-ahc-ws-3.0.0-M2.jar:3.0.0-M2]
      at org.apache.camel.support.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:66) ~[camel-support-3.0.0-M2.jar:3.0.0-M2]
      at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:130) ~[camel-core-3.0.0-M2.jar:3.0.0-M2]
      at org.apache.camel.processor.RedeliveryErrorHandler$RedeliveryState.run(RedeliveryErrorHandler.java:482) ~[camel-core-3.0.0-M2.jar:3.0.0-M2]
      at org.apache.camel.support.ReactiveHelper$Worker.schedule(ReactiveHelper.java:130) [camel-support-3.0.0-M2.jar:3.0.0-M2]
      at org.apache.camel.support.ReactiveHelper.scheduleMain(ReactiveHelper.java:43) [camel-support-3.0.0-M2.jar:3.0.0-M2]
      at org.apache.camel.processor.Pipeline.process(Pipeline.java:88) [camel-core-3.0.0-M2.jar:3.0.0-M2]
      at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:221) [camel-core-3.0.0-M2.jar:3.0.0-M2]
      at org.apache.camel.component.seda.SedaConsumer.sendToConsumers(SedaConsumer.java:289) [camel-seda-3.0.0-M2.jar:3.0.0-M2]
      at org.apache.camel.component.seda.SedaConsumer.doRun(SedaConsumer.java:203) [camel-seda-3.0.0-M2.jar:3.0.0-M2]
      at org.apache.camel.component.seda.SedaConsumer.run(SedaConsumer.java:148) [camel-seda-3.0.0-M2.jar:3.0.0-M2]
      at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1135) [na:na]
      at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) [na:na]
      at java.base/java.lang.Thread.run(Thread.java:844) [na:na]
  </code></pre>
  
  <p>While debugging we found that the <code>org.apache.camel.component.ahc.ws.WsProducer</code> tries to send the message with a <code>org.apache.camel.component.ahc.ws.WebSocket</code> object which, in our case, is <code>null</code>:</p>
  
  <p><a href="https://i.stack.imgur.com/8TW1W.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/8TW1W.png" alt="WsProducer"></a></p>
  
  <p>However the component seems to be plugged-in properly because sending to a non-secured WS endpoint for test purposes worked as expected. It then also only produces the "Reconnecting websocket" log once.</p>
  
  <h3>Questions</h3>
  
  <p>Did anyone already face a similar problem while authenticating during the WS handshake?</p>
  
  <p>We already looked up the configuration possibilities of the AHC-WS component, but none of them seem to fit for this case.</p>
  
  <p>Additionally, we need to generate and add the token dynamically, so hard-coding it wouldn't help.</p>