Search code examples
javaretrofit2

Why does my retrofit always get the query with old tokens?


In my app I use Retrofit2 with a service to collect data on eBay. For this I need a token that is valid for 2 hours.

If I start the query, the token is taken over from my database and works. If the 2 hours have expired, the token will be re-entered in the database. But when the data is picked up again on Ebay, I get an error 401 - unauthorized access. I use a MainActivity and invite the fragments there. As soon as I restart the app, everything works again. I suspect that the service does not update the token when query and use the old token. How can I end the service or query and start with the new token? What could be the problem?

public class RetrofitClient {
    private static Retrofit retrofit = null;

    public static Retrofit getClient(String baseUrl, String token) {
        if (retrofit == null) {

            String auth = "Bearer " + token;
            String cont = "application/json";

            OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();

            okHttpClient.addInterceptor(chain -> {
                Request request = chain.request().newBuilder()
                        .addHeader("Authorization", auth)
                        .addHeader("Content-Type", cont)
                        .build();
                return chain.proceed(request);
            });

            retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(okHttpClient.build())
                    .build();
        }
        return retrofit;
    }

When picking up the token from the database, according to log, the current token is always read out. But the feedback from eBay is always the 401 error.

Edit: The OkHttp connection keeps the token. Since the same address is called up, the previous connection with the old token is used. How can I replace/replace the token?


Solution

  • Your method has the below logic:

    private static Retrofit retrofit = null;
    
    public static Retrofit getClient(String baseUrl, String token) {
        if (retrofit == null) {
           // ...
        }
        return retrofit;
    }
    

    Because retrofit is defined as static it will keep its given value from the moment it's first assigned / even without the static keyword it would keep that value for the duration of the instantiated object's lifetime.

    The first time getClient is called the value is null, so the logic in the if block is run & the retrofit gets defined with an Authorization header which includes the given token value.

    However, subsequent calls to getClient will see that retrofit is already assigned, so will just return it; regardless of what parameters were sent to the method (i.e. even if there's a new token), and as the variable is static this will be true even if you've created a new instance of your RetrofitClient.

    There are various solutions:

    1. Remove the if statement so that the logic within it is run every time. This will incur some performance overhead (i.e. as you're having to do work for every request, even if the baseUrl and token values are the same as previously), but will return a Retrofit instance with the correct values every time. If doing this, you may not need the private static Retrofit retrofit = null; line at all; as the value is created and returned entirely within your getClient method; so making the value accessible outside of this context just adds risk.

    2. Remove the static keyword and create a new instance of the RetrofitClient class for each new baseUrl + token value (i.e. each time your token expires). This may require additional refactoring, as you'll then require an instance of your class to access the getClient method.

    3. Add code such as below, to check if the values are different to previous requests and update retrofit only when required. E.g.

    private static Retrofit retrofit = null;
    private static String baseUrlCached = null;
    private static String tokenCached = null;
    
    public static Retrofit getClient(String baseUrl, String token) {
        if (retrofit == null || (baseUrl != baseUrlCached || token != tokenCached)) {
           // ...
        }
        return retrofit;
    }