Files
spring-boot-demo/restclient-basic-auth/docs/02-restclient-basic-auth-patterns.md
T
Claude e4b5636f7c Add custom-validation, etag-caching, restclient-basic-auth: Boot 4.1 API pass
Three companion modules verifying and rewriting the Boot 4.1.1 / Framework
7.0.9 story for three older articles: the javax->jakarta.validation namespace
fix plus Jakarta Validation 3.1 record-validation clarification, ETag/
conditional-request APIs re-verified unchanged plus the starter rename, and
RestTemplate Basic Auth rebuilt on RestClient with the exchange() trap called
out. 19 real passing tests generate every transcript quoted from the three
companion articles.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EQNA6DJ9VgCtW6zhCE8Xud
2026-09-19 10:17:09 +00:00

3.5 KiB

2. RestClient with Basic Auth, two ways

Prev: {noop} passwords | README | Next: The starter split, and the exchange() trap

Source: RestClientConfig.java, ApiClient.java. Test: RestClientBasicAuthTest.java. Transcripts: docs/output/01-restclient-basic-auth-default-headers.txt, docs/output/02-restclient-basic-auth-interceptor.txt.

The original article's two RestTemplate patterns -- RestTemplateBuilder.basicAuthentication(...) and a hand-added BasicAuthenticationInterceptor -- both have a direct RestClient equivalent. Both are built on the auto-configured RestClient.Builder injected as a constructor parameter, never RestClient.create(), which carries none of Boot's message converters, observability, or customizer beans -- the same rule the RestTemplate to RestClient migration guide covers in more general depth.

Idiomatic on RestClient: defaultHeaders + setBasicAuth

@Bean
public RestClient restClientWithDefaultHeaders(RestClient.Builder builder) {
    return builder
            .defaultHeaders(headers -> headers.setBasicAuth("admin", "password123"))
            .build();
}
Response: Hello, you have accessed a secured endpoint!

(docs/output/01-restclient-basic-auth-default-headers.txt) -- a real HTTP call against a real embedded Tomcat with a real Spring Security filter chain, not a mock.

Ported unchanged: BasicAuthenticationInterceptor

@Bean
public RestClient restClientWithInterceptor(RestClient.Builder builder) {
    return builder
            .requestInterceptor(new BasicAuthenticationInterceptor("admin", "password123"))
            .build();
}

BasicAuthenticationInterceptor implements ClientHttpRequestInterceptor -- the exact same interface both RestTemplate.getInterceptors() and RestClient.Builder.requestInterceptor(...) accept, so this class needs no changes at all to move from one client to the other. Same result: docs/output/02-restclient-basic-auth-interceptor.txt.

Prefer defaultHeaders when the credentials are fixed at bean-creation time; keep the interceptor form when credentials must be resolved per request (a token fetched from a vault, say) -- an interceptor runs on every call, a defaultHeaders value is captured once.

The negative cases, checked too

docs/output/03-restclient-no-credentials-401.txt and 04-restclient-wrong-password-401.txt confirm what actually happens on the failure path: retrieve() throws HttpClientErrorException.Unauthorized on a 401, exactly like RestTemplate did -- this is the default retrieve() behaviour, not the exchange() behaviour covered in the next chapter.

Going deeper