1
0
Files

3.2 KiB

5. The gateway, and what TokenRelay actually relays

Prev: 4. What is not validated · Next: 6. mTLS

Spring Cloud Gateway Server MVC ships a filter that sounds like it solves the whole problem:

filters:
  - TokenRelay=

It is TokenRelayFilterFunctions, with two forms:

public static HandlerFilterFunction<ServerResponse, ServerResponse> tokenRelay();
public static HandlerFilterFunction<ServerResponse, ServerResponse> tokenRelay(String clientRegistrationId);

The documentation is precise about what it does, and it is not what the name suggests to most readers: it takes the access token of the currently authenticated user — the one obtained by oauth2Login() — or of the named client registration, and puts it in the Authorization header of the proxied request.

It does not mean "forward the incoming bearer token". There is nothing to forward from if the gateway never performed a login.

The A/B

gateway.yml defines two routes to the same destination, differing only in the filter. docs/output/04-gateway-token-relay.txt:

/edge/relay     (TokenRelay=)     → 200, sub: alice
/norelay/x      (no TokenRelay)   → 200, sub: alice

Identical. The token arrived because the gateway proxied the Authorization header the caller sent, which it would have done anyway. In this configuration TokenRelay contributes nothing.

Where it earns its place is the other shape: a gateway that terminates a browser session with oauth2Login(), keeps the tokens server-side, hands the browser nothing but a session cookie, and attaches a token on the way through. That is the backend-for-frontend pattern, and it is a genuinely good answer to "where do I keep the token in a SPA" — because the answer is "not in the SPA".

The 401 that has nothing to do with OAuth

Before GatewaySecurityConfig existed, every call through the gateway came back:

HTTP/1.1 401
WWW-Authenticate: Basic realm="Realm", charset="UTF-8"

A perfectly valid bearer token, rejected by a gateway that had never been told to expect one. Spring Boot applies a default filter chain — HTTP Basic and form login over every path — to any application on the classpath with Spring Security and no SecurityFilterChain bean. A gateway is an application. WWW-Authenticate: Basic in front of a token-based estate always means this.

Choosing where the gateway sits

Shape Gateway does Downstream sees
Pass-through Routes; validates nothing The caller's token; each service validates it
Edge validation Validates the token, strips it, adds its own identity The gateway's identity
BFF oauth2Login(), holds tokens, TokenRelay The user's token, obtained by the gateway

Pass-through is the default and is fine while every service validates properly — chapter 4 is about how often that assumption is wrong. Edge validation is the one that tempts teams into "the gateway checked it, so we can trust the header", which is chapter 6's failure mode wearing a different hat.


Prev: 4. What is not validated · Next: 6. mTLS