@@ -152,7 +152,8 @@ public class Client implements AutoCloseable {
152152 private final ColumnToMethodMatchingStrategy columnToMethodMatchingStrategy ;
153153
154154 private Client (Set <String > endpoints , Map <String ,String > configuration , boolean useNewImplementation ,
155- ExecutorService sharedOperationExecutor , ColumnToMethodMatchingStrategy columnToMethodMatchingStrategy ) {
155+ ExecutorService sharedOperationExecutor , ColumnToMethodMatchingStrategy columnToMethodMatchingStrategy ,
156+ Supplier <String > bearerTokenSupplier ) {
156157 this .endpoints = endpoints ;
157158 this .configuration = configuration ;
158159 this .endpoints .forEach (endpoint -> {
@@ -169,7 +170,7 @@ private Client(Set<String> endpoints, Map<String,String> configuration, boolean
169170 }
170171 this .useNewImplementation = useNewImplementation ;
171172 if (useNewImplementation ) {
172- this .httpClientHelper = new HttpAPIClientHelper (configuration );
173+ this .httpClientHelper = new HttpAPIClientHelper (configuration , bearerTokenSupplier );
173174 LOG .info ("Using new http client implementation" );
174175 } else {
175176 this .oldClient = ClientV1AdaptorHelper .createClient (configuration );
@@ -219,6 +220,8 @@ public static class Builder {
219220 private ExecutorService sharedOperationExecutor = null ;
220221 private ColumnToMethodMatchingStrategy columnToMethodMatchingStrategy ;
221222
223+ private Supplier <String > bearerTokenSupplier = null ;
224+
222225 public Builder () {
223226 this .endpoints = new HashSet <>();
224227 this .configuration = new HashMap <String , String >();
@@ -886,6 +889,32 @@ public Builder useHTTPBasicAuth(boolean useBasicAuth) {
886889 return this ;
887890 }
888891
892+ /**
893+ * Specifies whether to use Bearer Authentication and what token to use.
894+ * The token will be sent as is, so it should be encoded before passing to this method.
895+ *
896+ * @param bearerToken - token to use
897+ * @return same instance of the builder
898+ */
899+ public Builder useBearerTokenAuth (String bearerToken ) {
900+ this .httpHeader ("Authorization" , "Bearer " + bearerToken );
901+ return this ;
902+ }
903+
904+ /**
905+ * Specifies a supplier for a bearer tokens. It is useful when token should be refreshed.
906+ * Supplier is called each time before sending a request.
907+ * Supplier should return encoded token.
908+ * This configuration cannot be used with {@link #useBearerTokenAuth(String)}.
909+ *
910+ * @param tokenSupplier - token supplier
911+ * @return
912+ */
913+ public Builder useBearerTokenAuth (Supplier <String > tokenSupplier ) {
914+ this .bearerTokenSupplier = tokenSupplier ;
915+ return this ;
916+ }
917+
889918 public Client build () {
890919 setDefaults ();
891920
@@ -896,15 +925,22 @@ public Client build() {
896925 // check if username and password are empty. so can not initiate client?
897926 if (!this .configuration .containsKey ("access_token" ) &&
898927 (!this .configuration .containsKey ("user" ) || !this .configuration .containsKey ("password" )) &&
899- !MapUtils .getFlag (this .configuration , "ssl_authentication" )) {
900- throw new IllegalArgumentException ("Username and password (or access token, or SSL authentication) are required" );
928+ !MapUtils .getFlag (this .configuration , "ssl_authentication" , false ) &&
929+ !this .configuration .containsKey (ClientSettings .HTTP_HEADER_PREFIX + "Authorization" ) &&
930+ this .bearerTokenSupplier == null ) {
931+ throw new IllegalArgumentException ("Username and password (or access token or SSL authentication or pre-define Authorization header) are required" );
901932 }
902933
903934 if (this .configuration .containsKey ("ssl_authentication" ) &&
904935 (this .configuration .containsKey ("password" ) || this .configuration .containsKey ("access_token" ))) {
905936 throw new IllegalArgumentException ("Only one of password, access token or SSL authentication can be used per client." );
906937 }
907938
939+ if (this .configuration .containsKey (ClientSettings .HTTP_HEADER_PREFIX + "Authorization" ) &&
940+ this .bearerTokenSupplier != null ) {
941+ throw new IllegalArgumentException ("Bearer token supplier cannot be used with a predefined Authorization header" );
942+ }
943+
908944 if (this .configuration .containsKey ("ssl_authentication" ) &&
909945 !this .configuration .containsKey (ClickHouseClientOption .SSL_CERTIFICATE .getKey ())) {
910946 throw new IllegalArgumentException ("SSL authentication requires a client certificate" );
@@ -943,7 +979,15 @@ public Client build() {
943979 throw new IllegalArgumentException ("Nor server timezone nor specific timezone is set" );
944980 }
945981
946- return new Client (this .endpoints , this .configuration , this .useNewImplementation , this .sharedOperationExecutor , this .columnToMethodMatchingStrategy );
982+ // check for only new implementation configuration
983+ if (!this .useNewImplementation ) {
984+ if (this .bearerTokenSupplier != null ) {
985+ throw new IllegalArgumentException ("Bearer token supplier cannot be used with old implementation" );
986+ }
987+ }
988+
989+ return new Client (this .endpoints , this .configuration , this .useNewImplementation , this .sharedOperationExecutor ,
990+ this .columnToMethodMatchingStrategy , this .bearerTokenSupplier );
947991 }
948992
949993 private static final int DEFAULT_NETWORK_BUFFER_SIZE = 300_000 ;
0 commit comments