1

I am trying to request Nest structures via Nest API, using Retrofit 1.9 on Android.

Could not be simpler: obtaining auth token works fine, then I issue HTTP GET request with Authorization header = "Bearer TOKEN". The query works via Postman and APC clients. However, in the Android app I am getting "unauthorized" response. (I see it in the Android Monitor).

Any clues?

public void nestGetStructures(final String token, Callback<JsonElement> c)
{
    final String uri = "https://developer-api.nest.com";

    RequestInterceptor requestInterceptor = new RequestInterceptor() {
        @Override
        public void intercept(RequestFacade request) {
            request.addHeader("Authorization", "Bearer" + token);
        }
    };

    RestAdapter restAdapter = new RestAdapter.Builder()
            .setLogLevel(RestAdapter.LogLevel.FULL)
            .setEndpoint(uri)
            .setRequestInterceptor(requestInterceptor)
            .build();

    NestService nestService = restAdapter.create(NestService.class);
    nestService.get_structures(c);

}

public interface NestService {

    @GET("/structures")
    void get_structures(    Callback<JsonElement> callback );

}

Would greatly appreciate suggestions.

VitalyR
  • 185
  • 1
  • 3
  • 11

2 Answers2

1

I'll put this here because it's longer than a comment, but it won't be a full answer because it's based on assumptions.

First and the easiest thing to spot is this:

request.addHeader("Authorization", "Bearer" + token);

This actually doesn't do what you describe. It doesn't really add Authorization: Bearer TOKEN, but it adds Authorization: BearerTOKEN. As you can see there's a lack of space between Bearer and TOKEN which will lead to a possible unauthorised error. If this is a typo in the question you posted and in your code there's actually a space, here's what you can do.

My past experience leads me to believe that every time someone says "... it works via Postman and APC... insert more REST clients here..." it's because these tools add their own headers to the call that the user is unaware. These headers are not automatically added by retrofit and somehow the backend server doesn't cope with this.

I would recommend you to check these headers and compare them with the ones your retrofit call is sending (log them and check them). If some are missing try and add them.

Hope this gets you started.

Fred
  • 16,367
  • 6
  • 50
  • 65
  • Thanks Fred, I tried with and without space, and tried adding the headers which postman/apc does. It does not work here and always works in clients. Ended up routing request via backend server (there are no performance/timing requirements) and it worked like a charm. – VitalyR Apr 20 '16 at 17:17
  • Cool, glad you got it working. If you still need help maybe we can do give it to you if you want to edit your question to add the logs and the changes you did. Cheers! – Fred Apr 21 '16 at 07:29
1

I was having same problem. It was related to my permission. Check your permission. Here is my implementation in retrofit 2:

public class ApiBuilder {
private static String BASE_URL = "https://developer-api.nest.com";
OkHttpClient defaultHttpClient;
NestToken mAccessToken;


/**
 * Construct a new {@code ApiBuilder}.
 *
 * @return an instance of {@link ApiBuilder}
 * @param accessToken
 */
public ApiBuilder(NestToken accessToken) {
    this.mAccessToken=accessToken;
    buildClient(mAccessToken);
}

private void buildClient(final NestToken accessToken) {
    //final String basic =
    //        "Bearer " + Base64.encodeToString(accessToken.getBytes(), Base64.NO_WRAP);
    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    /**
     * set your desired log level
     * */
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    defaultHttpClient = new OkHttpClient.Builder()
            .addNetworkInterceptor(
                    new Interceptor() {
                        @Override
                        public Response intercept(Chain chain) throws IOException {
                            Request request = chain.request().newBuilder()
                                    .addHeader("Authorization", "Bearer "+accessToken.getToken())
                                    .addHeader("Content-Type", "application/json").build();
                            return chain.proceed(request);
                        }
                    }).addInterceptor(logging).build();
}



/**
 * Initiate a {@link ApiService} instance.
 *
 * @return an instance of {@link ApiService}.
 */
public ApiService createApiService() {
    Gson gson = new GsonBuilder()
            .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
            .create();
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(defaultHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    ApiService apiService = retrofit.create(ApiService.class);
    return apiService;
}

}

to get all information:

public interface ApiService {


@Headers("Cache-Control: max-age=640000")
@GET("/")
Call<ResponseBody> getAllDataAndStructure();

}

I just get a Retrofit ResponseBody and parsed it by myself.

Omar Faroque Anik
  • 2,531
  • 1
  • 29
  • 42