java 92 lines · 3 tabs

Attaching Bearer Tokens to Spring RestClient Calls with a ClientHttpRequestInterceptor

Shared by codesnips Sep 2026
3 tabs
package com.example.http;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class BearerTokenInterceptor implements ClientHttpRequestInterceptor {

    private final TokenProvider tokenProvider;

    public BearerTokenInterceptor(TokenProvider tokenProvider) {
        this.tokenProvider = tokenProvider;
    }

    @Override
    public ClientHttpResponse intercept(HttpRequest request,
                                        byte[] body,
                                        ClientHttpRequestExecution execution) throws IOException {
        HttpHeaders headers = request.getHeaders();
        // Respect an explicit override set by the caller.
        if (!headers.containsKey(HttpHeaders.AUTHORIZATION)) {
            headers.setBearerAuth(tokenProvider.getToken());
        }
        return execution.execute(request, body);
    }
}
3 files · java Explain with highlit

This snippet shows how outgoing REST calls made through Spring's RestClient can be transparently enriched with an Authorization header, so business code never touches token plumbing. The pattern relies on a ClientHttpRequestInterceptor, which sits in the request pipeline and can mutate headers before the call is executed and inspect the response after. Centralizing auth in an interceptor avoids the classic mistake of sprinkling header-building logic across every service method, which drifts and rots over time.

In BearerTokenInterceptor, the class implements ClientHttpRequestInterceptor and overrides intercept. It reads a token from a TokenProvider, sets HttpHeaders.AUTHORIZATION to Bearer <token>, then delegates to execution.execute(request, body) to continue the chain. A subtle but important detail is that the interceptor is idempotent: it only adds the header when one is not already present, so a caller that wants to override credentials for a specific request still can. Because interceptors run for every request through the client, keeping the work cheap matters — hence the token is fetched from a cached provider rather than minted on each call.

TokenProvider demonstrates that caching. It holds a volatile cachedToken guarded by an expiry timestamp and refreshes only when the token is missing or within a safety EXPIRY_SKEW window of expiring. This clock-skew buffer is a common pitfall: fetching a token that is technically valid but expires mid-flight leads to sporadic 401s, so refreshing slightly early is safer. The double-checked pattern inside synchronized keeps concurrent callers from stampeding the auth server.

RestClientConfig wires everything together as an idiomatic Spring @Configuration. It builds a RestClient via RestClient.builder(), registers the interceptor with requestInterceptor, and sets a baseUrl, producing a ready-to-inject bean. Any collaborator that injects this RestClient automatically gets authenticated requests.

The main trade-off is that a globally-registered interceptor applies to every request through that client, so distinct downstreams needing different credentials should get separate RestClient beans. When one downstream and one identity are involved, this approach is clean, testable, and keeps cross-cutting auth concerns out of the domain layer.


Related snips

ruby
payload = {
  sub: user.id,
  iss: 'https://auth.example.com',
  aud: 'codesnips-api',
  exp: 15.minutes.from_now.to_i,
  iat: Time.now.to_i,

JWT issuance and verification without common footguns

jwt authentication api
by Kai Nakamura 2 tabs
typescript
export interface RetryOptions {
  retries: number;
  baseMs: number;
  maxMs: number;
  signal?: AbortSignal;
  onRetry?: (attempt: number, delay: number, err: unknown) => void;

Exponential backoff with jitter for retries

typescript reliability retry
by codesnips 2 tabs
graphql
type User {
    id: ID!
    name: String!
    email: String!
    posts: [Post!]!
    createdAt: String!

GraphQL API with Spring Boot

java graphql spring-boot
by David Kumar 3 tabs
java
package com.example.starter.config;

import com.example.starter.properties.CustomProperties;
import com.example.starter.service.CustomService;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;

Custom Spring Boot starters

java spring-boot starter
by David Kumar 4 tabs
typescript
import { randomBytes, createHash } from "crypto";
import jwt from "jsonwebtoken";
import { RefreshTokenStore } from "./store";

const ACCESS_SECRET = process.env.ACCESS_SECRET!;
const ACCESS_TTL = "15m";

JWT access + refresh token rotation (conceptual)

security node jwt
by codesnips 3 tabs
go
package deps

import (
  "net"
  "net/http"
  "time"

HTTP client tuned for production: timeouts, transport, and connection reuse

go http client
by Leah Thompson 1 tab

Share this code

Here's the card — post it anywhere.

Attaching Bearer Tokens to Spring RestClient Calls with a ClientHttpRequestInterceptor — share card
Link copied