Reputation: 498
I have a custom API set up on AWS for passing a message to the server. The server then responds to that message in a simple fashion. The API calls work from the browser and Postman, but do not work via the mobile client. I've removed authorization on the API, deployed it, and triple checked my api calls, but I continue to receive the 403 "Forbidden" error. I'm calling the API using Retrofit. Here is my client code:
API Calls:
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Headers;
import retrofit2.http.POST;
public interface MyAPI {
@Headers({
"content-type: application/json",
"Accept: application/json"
})
@POST("/chat/new")
Call<ChatMessageBody> postMessage(@Body ChatMessageBody message);
}
ChatMessageBody class:
public class ChatMessageBody {
private String messageBody;
public ChatMessageBody(String body){
this.messageBody = body;
}
public String body() {
return messageBody;
}
}
Theoretically, the Request Body of my call as a result of the set up should be something like this:
{
"messageBody" : "This is my message"
}
Am I missing a vital aspect of calling the API from a mobile setting? It doesn't make sense to me that I'd be able to call the API endpoint from my browser and through Postman and have it work, yet I can't seem to do so via Android.
EDIT: Response Body from a successful call (via postman or API Gateway test)
{\"messageBody\": \"You said \\\"test\\\"\"}
Response Body from the 403 error
{"message":"Forbidden"}
Postman generates code based on your desired client and your calls. Here is the code generated for this call by Postman (with respect to OkHTTP. I'm not using this code, but it could provide insight into why Postman works and my client doesn't):
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n\t\"messageBody\" : \"test\"\n}");
Request request = new Request.Builder()
.url("https://qj2wkyi91c.execute-api.us-east-1.amazonaws.com/prototype_mvp/chat/new")
.post(body)
.addHeader("content-type", "application/json")
.addHeader("cache-control", "no-cache")
.addHeader("postman-token", "dccf1f20-f20e-fd53-dd24-a9f4ae7b5c69")
.build();
Response response = client.newCall(request).execute();
Here is a stack trace of my requests/responses in the Android Environment:
03-27 12:32:27.835 29985-31080/com.dev.example.debug D/OkHttp: --> POST [MY_API_ENDPOINT] http/1.1
03-27 12:32:27.835 29985-31080/com.dev.example.debug D/OkHttp: Content-Type: application/json
03-27 12:32:27.835 29985-31080/com.dev.example.debug D/OkHttp: Content-Length: 36
03-27 12:32:27.835 29985-31080/com.dev.example.debug D/OkHttp: Accept: application/json
03-27 12:32:27.836 29985-31080/com.dev.example.debug D/OkHttp: {"messageBody":"This is my message"}
03-27 12:32:27.836 29985-31080/com.dev.example.debug D/OkHttp: --> END POST (36-byte body)
03-27 12:32:28.076 29985-31080/com.dev.example.debug D/OkHttp: <-- 403 [MY_API_ENDPOINT] (239ms)
03-27 12:32:28.076 29985-31080/com.dev.example.debug D/OkHttp: content-type: application/json
03-27 12:32:28.076 29985-31080/com.dev.example.debug D/OkHttp: content-length: 24
03-27 12:32:28.076 29985-31080/com.dev.example.debug D/OkHttp: date: Mon, 27 Mar 2017 16:32:28 GMT
03-27 12:32:28.076 29985-31080/com.dev.example.debug D/OkHttp: x-amzn-requestid: [REQUEST_ID]
03-27 12:32:28.076 29985-31080/com.dev.example.debug D/OkHttp: x-amzn-errortype: ForbiddenException
03-27 12:32:28.076 29985-31080/com.dev.example.debug D/OkHttp: x-cache: Error from cloudfront
03-27 12:32:28.076 29985-31080/com.dev.example.debug D/OkHttp: via: 1.1 [CLOUDFRONT_URL] (CloudFront)
03-27 12:32:28.077 29985-31080/com.dev.example.debug D/OkHttp: x-amz-cf-id: [CF_ID]
03-27 12:32:28.077 29985-31080/com.dev.example.debug D/OkHttp: {"message":"Forbidden"}
03-27 12:32:28.077 29985-31080/com.dev.example.debug D/OkHttp: <-- END HTTP (24-byte body)
03-27 12:32:28.079 29985-29985/com.dev.example.debug E/MyAPI: Your request did not receive a successful response.
03-27 12:32:28.079 29985-29985/com.dev.example.debug E/MyAPI: Response Error Code: 403
03-27 12:32:28.079 29985-29985/com.dev.example.debug E/MyAPI: Response Body: {"message":"Forbidden"}
Upvotes: 2
Views: 2568
Reputation: 1673
Created an AWS Gateway OkHttp Interceptor for those who prefer Retrofit over the AWS sdk. It still uses AWS4Signer
from aws-android-sdk-apigateway-core
tho, so you have to keep this dependency in your project.
Upvotes: 0
Reputation: 498
I ended up solving this issue by abandoning Retrofit and designing an OKHttp client which interfaces with AWS. My requests are now being properly signed for AWS, and I'm no longer receiving 403 errors.
Upvotes: 0
Reputation: 9040
403 (Permission Denied) can also occur if you send a request to the wrong path.
I'm not familiar with retrofit, but see you only have /chat/new
listed in your annotation. How do you configure the root path in retrofit?
Are you sure you are including the full path including stage?
Upvotes: 0
Reputation: 3863
There is no authorization in that request, therefore the response given back is forbidden accessing that route.
Also the content type can affect that, postman conveniently deals with this behind the scenes, application/x-www-form-urlencoded
.
Upvotes: 2