OpenFeign / OpenFeign/feign

Unexpected FeignException instead of ResponseEntity when the server returns 401

Open
#2,312 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feedback provided
Dominant language
Java
Stars
9.8k
Forks
1.9k
Avg merge
1d 2h
Merged PRs (30d)
41

Description

Originally asked in https://stackoverflow.com/questions/77880702/unexpected-feignexception-instead-of-responseentity-when-the-server-returns-401

In our application we use spring-cloud-starter-openfeign:4.1.0 for some interservice communication. Here's one of our clients:

@FeignClient(name = "authClient", url = "${spring.microservice.tenant-auth.host}")
public interface AuthClient {
    @PostMapping(consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    ResponseEntity<AuthenticationResponse> getAuthToken(AuthFormData formData);
}

public class AuthFormData {

    private String grant_type;
    private String client_id;
    private String client_secret;

    public void setGrantType(String grantType) {
        this.grant_type = grantType;
    }

    public void setClientId(String clientId) {
        this.client_id = clientId;
    }

    public void setClientSecret(String clientSecret) {
        this.client_secret = clientSecret;
    }
}

public class AuthenticationResponse {

    @JsonProperty("access_token")
    private String accessToken;
    @JsonProperty("token_type")
    private String tokenType;
    @JsonProperty("expires_in")
    private int expiresIn;
    @JsonProperty("scope")
    private String scope;
    @JsonProperty("refresh_token")
    private String refreshToken;
    @JsonProperty("id_token")
    private String idToken;
}

In general this code works fine, but what puzzles me is the FeignException thrown from the callee in case the server returns 401:

AuthenticationResponse getToken(AuthFormData authFormData) {
    var authResponse = authClient.getAuthToken(authFormData);
    var body = authResponse.getBody();
    if (!authResponse.getStatusCode().is2xxSuccessful() || body == null) {
        throw new IllegalStateException("Failed to get auth token " + authResponse);
    }
    return body;
}

Here's the stacktrace:

feign.FeignException$Unauthorized: [401 Unauthorized] during [POST] to [https://somethin.com/oauth/token] [AuthClient#getAuthToken(AuthFormData)]: []
	at feign.FeignException.clientErrorStatus(FeignException.java:224) ~[feign-core-13.1.jar:na]
	at feign.FeignException.errorStatus(FeignException.java:203) ~[feign-core-13.1.jar:na]
	at feign.FeignException.errorStatus(FeignException.java:194) ~[feign-core-13.1.jar:na]
	at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:103) ~[feign-core-13.1.jar:na]
	at feign.InvocationContext.decodeError(InvocationContext.java:126) ~[feign-core-13.1.jar:na]
	at feign.InvocationContext.proceed(InvocationContext.java:72) ~[feign-core-13.1.jar:na]
	at feign.ResponseHandler.handleResponse(ResponseHandler.java:63) ~[feign-core-13.1.jar:na]
	at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:114) ~[feign-core-13.1.jar:na]
	at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:70) ~[feign-core-13.1.jar:na]
	at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:99) ~[feign-core-13.1.jar:na]
	at jdk.proxy2/jdk.proxy2.$Proxy113.getAuthToken(Unknown Source) ~[na:na]
	at c.c.o.p.m.AuthenticationTokenProvider.getToken(AuthenticationTokenProvider.java:34) ~[classes/:0.0.1-SNAPSHOT]

If the response is 200 or 500 then the ResponseEntity with corresponding status code is returned.

So my question is why do I get exception for 401 and is there a way to make the AuthClient return ResponseEntity with 401?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the supplied AuthClient call with 401, 200, and 500 responses, then trace ErrorDecoder$Default.decode through InvocationContext, ResponseHandler, and SynchronousMethodHandler. Compare the status-handling paths and inspect the Feign response-decoding entry points. Done means the 401 behavior is explained and, if changed, covered alongside the existing 200 and 500 behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.