# 2. RestClient with Basic Auth, two ways [Prev: {noop} passwords](01-password-encoding.md) | [README](../README.md) | Next: [The starter split, and the exchange() trap](03-starter-split-and-exchange-trap.md) Source: [`RestClientConfig.java`](../src/main/java/com/ankurm/restclientbasicauth/client/RestClientConfig.java), [`ApiClient.java`](../src/main/java/com/ankurm/restclientbasicauth/client/ApiClient.java). Test: [`RestClientBasicAuthTest.java`](../src/test/java/com/ankurm/restclientbasicauth/RestClientBasicAuthTest.java). Transcripts: [`docs/output/01-restclient-basic-auth-default-headers.txt`](output/01-restclient-basic-auth-default-headers.txt), [`docs/output/02-restclient-basic-auth-interceptor.txt`](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](https://ankurm.com/resttemplate-to-restclient-migration-guide/) covers in more general depth. ## Idiomatic on RestClient: `defaultHeaders` + `setBasicAuth` ```java @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`](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` ```java @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`](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 - [`RestClient` Javadoc](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestClient.html) (rel="nofollow") - Prev: [{noop} passwords](01-password-encoding.md) - Next: [The starter split, and the exchange() trap](03-starter-split-and-exchange-trap.md)