Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

- allow format options to be applied to the http response decoding.

### Fixed

- Fixed Bearer token casing in OIDC Authorization header from "BEARER" to "Bearer" to comply with RFC 6750.

## [0.24.0] - 2025-11-26

- Add UNABLE_TO_DESERIALIZE_RESPONSE http-completion-state. If you have used
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@ public String preprocessHeaderValue(String rawValue) {
oidcExpiryReduction
);
// apply the OIDC authentication by adding the dynamically calculated header value.
return "BEARER " + auth.authenticate();
return "Bearer " + auth.authenticate();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package com.getindata.connectors.http.internal;

import java.time.Duration;
import java.util.Optional;

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static org.assertj.core.api.Assertions.assertThat;

class OIDCAuthHeaderValuePreprocessorTest {

private static final int SERVER_PORT = 9091;
private static final String TOKEN_ENDPOINT = "/oauth/token";

private WireMockServer wireMockServer;

@BeforeEach
public void setup() {
wireMockServer = new WireMockServer(
WireMockConfiguration.wireMockConfig().port(SERVER_PORT)
);
wireMockServer.start();
}

@AfterEach
public void tearDown() {
wireMockServer.stop();
}

@Test
public void shouldReturnBearerTokenWithCorrectCasing() {
// Setup mock OIDC token endpoint
String accessToken = "test_access_token_12345";
wireMockServer.stubFor(post(urlEqualTo(TOKEN_ENDPOINT))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("{\"access_token\": \"" + accessToken + "\", \"expires_in\": 3600}")
));

String tokenEndpointUrl = "http://localhost:" + SERVER_PORT + TOKEN_ENDPOINT;
String tokenRequest = "grant_type=client_credentials&client_id=test&client_secret=secret";

OIDCAuthHeaderValuePreprocessor preprocessor = new OIDCAuthHeaderValuePreprocessor(
tokenEndpointUrl,
tokenRequest,
Optional.of(Duration.ofSeconds(1))
);

String headerValue = preprocessor.preprocessHeaderValue("ignored");

// Verify the Bearer token uses correct RFC 6750 casing ("Bearer" not "BEARER")
assertThat(headerValue).startsWith("Bearer ");
assertThat(headerValue).isEqualTo("Bearer " + accessToken);
// Explicitly verify it's NOT using uppercase BEARER
assertThat(headerValue).doesNotStartWith("BEARER ");
}

@Test
public void shouldReturnBearerTokenWithDefaultExpiryReduction() {
// Setup mock OIDC token endpoint
String accessToken = "another_test_token";
wireMockServer.stubFor(post(urlEqualTo(TOKEN_ENDPOINT))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("{\"access_token\": \"" + accessToken + "\", \"expires_in\": 3600}")
));

String tokenEndpointUrl = "http://localhost:" + SERVER_PORT + TOKEN_ENDPOINT;
String tokenRequest = "grant_type=client_credentials";

OIDCAuthHeaderValuePreprocessor preprocessor = new OIDCAuthHeaderValuePreprocessor(
tokenEndpointUrl,
tokenRequest,
Optional.empty()
);

String headerValue = preprocessor.preprocessHeaderValue("any_raw_value");

// Verify correct Bearer casing per RFC 6750
assertThat(headerValue).startsWith("Bearer ");
assertThat(headerValue).isEqualTo("Bearer " + accessToken);
}
}
Loading