Retrofit Authenticator called but not work

551 Views Asked by At

at the first I am sorry for my poor english. I am developing an android app with nodejs backend.JWT is used for authorization, so I send access token to the server to authorize my request. access token life is short and expire in 60s. for refreshing the access token the app must to send refresh token to server. for this purpose I am using OkHttp authenticator but authenticator is not work. can any body help me to solve this problem

ServiceGenerator

public class ServiceGenerator {

    private static final OkHttpClient httpClient =
            new OkHttpClient.Builder()
                    .retryOnConnectionFailure(true)
                    .build();

    private static final Retrofit.Builder builder =
            new Retrofit.Builder()
                    .baseUrl(API_BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create());

    public static Retrofit retrofit = builder.build();

    public static <S> S createService(Class<S> serviceClass) {
        Retrofit retrofit = builder.client(httpClient).build();
        return retrofit.create(serviceClass);
    }

    public static <S> S createServiceWithAuth(Class<S> serviceClass, String accessToken, Context context) {
        OkHttpClient newClient = httpClient.newBuilder().addInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {

                Request request = chain.request();
                Request.Builder builder = request.newBuilder();

                if(!accessToken.isEmpty()){
                    builder.addHeader("x-auth-token", accessToken);
                }
                request = builder.build();
                return chain.proceed((request));
            }
        }).authenticator(CustomAuthenticator.getInstance(accessToken, context))
                .build();
        Retrofit newRetrofit = retrofit.newBuilder().client(newClient).baseUrl(API_BASE_URL).addConverterFactory(GsonConverterFactory.create()).build();
        return newRetrofit.create(serviceClass);
    }

}

CustomAuthenticator


public class CustomAuthenticator implements Authenticator {

    private String accessToken;
    private static CustomAuthenticator INSTANCE;
    Context context;


    private CustomAuthenticator(String accessToken, Context context){
        this.accessToken = accessToken;
        Hawk.init(context).build();
        this.context = context;
    }

    static synchronized CustomAuthenticator getInstance(String accessToken, Context context){
        if(INSTANCE == null){
            INSTANCE = new CustomAuthenticator(accessToken, context);
        }
        return INSTANCE;
    }

    @Nullable
    @Override
    public Request authenticate(@Nullable Route route, @NotNull Response response) throws IOException {

        if(responseCount(response) >= 2){
            return null;
        }

        ApiClient client = ServiceGenerator.createService(ApiClient.class);
        User user = new User();
        user.setRefreshToken(Hawk.get("RefreshToken"));
        Call<User> refreshAccessTokenCall = client.refresh(user);
        retrofit2.Response<User> res = refreshAccessTokenCall.execute();

        if(res.isSuccessful()){
            assert res.body() != null;
            String accessToken = res.body().getAccessToken();
            Hawk.put("AccessToken", accessToken);

            return response.request().newBuilder().addHeader("x-auth-token", res.body().getAccessToken()).build();
        }else{
            return null;
        }
    }

    private int responseCount(Response response){
        int result = 1;
        while ((response = response.priorResponse()) != null){
            result++;
        }
        return result;
    }
}

and method that POST data to server (in Fragment)

    private void saveExpert() {

        if (!validate()) {
            return;
        }

        progressBar.setVisibility(View.VISIBLE);
        Objects.requireNonNull(getActivity()).getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);

        String first_and_last_name = firstAndLastName.getText().toString();
        String national_code = nationalCode.getText().toString();
        String phone_number = phoneNumber.getText().toString();
        String home_office_city = homeOfficeCity.getText().toString();
        String _address = address.getText().toString();
        String _field = field.getText().toString();
        String sub_field = subField.getText().toString();
        String _grade = grade.getText().toString();


        ApiClient client = ServiceGenerator.createServiceWithAuth(ApiClient.class, Hawk.get("AccessToken"), getContext());
        SetExpert setExpert = new SetExpert(first_and_last_name, national_code, phone_number, home_office_city, _address, _field, sub_field, _grade);
        Call<Expert> expertCall = client.saveExpert(setExpert);
        expertCall.enqueue(new Callback<Expert>() {
            @Override
            public void onResponse(@NotNull Call<Expert> call, @NotNull Response<Expert> response) {
                if (response.isSuccessful()) {
                    Expert expert = response.body();
                    if (expert != null) {
                        Hawk.init(Objects.requireNonNull(getContext())).build();
                        Hawk.put("ExpertNationalCode", expert.getNational_code());
                        progressBar.setVisibility(View.GONE);
                        Objects.requireNonNull(getActivity()).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
                        new MaterialDialog.Builder(Objects.requireNonNull(getContext()))
                                .typeface("IRANSansWebMedium.ttf", "IRANSansWeb.ttf")
                                .title("پیام سیستم")
                                .content(expert.getFirst_and_last_name() + " عزیز با تشکر از ثبت نام شما. این ثبت نام به منزله تایید نهایی نبوده و پس از بررسی مشخصات و مدارک، با شما تماس گرفته خواهد شد.")
                                .positiveText("تایید.")
                                .canceledOnTouchOutside(false)
                                .onPositive(new MaterialDialog.SingleButtonCallback() {
                                    @Override
                                    public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                                        dismiss();
                                    }
                                })
                                .show();
                    }
                } else {
                        ApiError apiError = ErrorUtils.parseError(response);
                        progressBar.setVisibility(View.GONE);
                        Objects.requireNonNull(getActivity()).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
                        Toast.makeText(getContext(), apiError.getMessage(), Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onFailure(@NotNull Call<Expert> call, @NotNull Throwable t) {
                progressBar.setVisibility(View.GONE);
                Objects.requireNonNull(getActivity()).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
                Toast.makeText(getContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
    }
1

There are 1 best solutions below

0
On

removeHeader("x-auth-token") may solve this.

return response.request().newBuilder()
    .removeHeader("x-auth-token") // Remove old header
    .addHeader("x-auth-token", res.body().getAccessToken())
    .build();

To prevent old "x-auth-token" from being sent, removeHeader() seems to be needed.