Search code examples
androidretrofit2multipartform-data

Signature issue while multipart "posting" with Retrofit on Android


I am having a problem trying to send data to my server using multipart/form-data

If I send only 2 parts (file included) I get an error 400 (saying I am missing the 2 others parts)

but if I send 3 or 4 parts I get an error 401 because my server respond with a signature issue.

here is my code. My Interface:

@POST("api/{id}/edit")
@Multipart
fun postMultipart(
    @Path("id") id: Int,
    @Part commissioner: MultipartBody.Part,
    @Part commissioning: MultipartBody.Part,
    @Part file: MultipartBody.Part?,
    @Part commissioningDate: MultipartBody.Part
): Call<ResponseBody>

So If I only send file and for example commissioner my server is responding 400 but if I send file and commissioner and commissioning my server is responding 401

I also tried MultipartBody.Part or RequestBody for other parts than the file (same result)

My AsyncTask making the call:

val interface = RetrofitSignedClient().getClient().create(Interface::class.java)

val f = getFile(context, fileUri)
val requestFile: RequestBody = f.asRequestBody()
val fileBody: MultipartBody.Part = MultipartBody.Part.createFormData("file", f.name, requestFile)

val commissionerIdPart =
    MultipartBody.Part.createFormData("commissioner", commissioner)

val commissioningPart =
    MultipartBody.Part.createFormData("commissioning", commissioning)

val datePart =
    MultipartBody.Part.createFormData("commissioningDate", date)

val response =
    interface.postMultipart(
        id = id,
        commissioner = commissionerIdPart,
        commissioning = commissioningPart,
        file = fileBody,
        commissioningDate = datePart
    ).execute()

The retrofit client:

val consumer = OkHttpOAuthConsumer(consumerKey, consumerSecret)
consumer.setTokenWithSecret(token, secret)

val client = OkHttpClient.Builder()
    .addInterceptor(SigningInterceptor(consumer)).build()

return Retrofit.Builder().baseUrl(WS_HOSTNAME_PROJECT)
    .addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create()))
    .client(client)
    .build()

For the 401 error, on phone logs I have 401 Unauthorized {"message":"An authentication exception occurred."}

and on server side:

Verification of signature failed (signature base string was "POST&http%3A%2F%2Fmy.server.address%2Fapi%2FID%2Fedit&commissioner%3D110000000292%26commissioning%3D0%26oauth_consumer_key%3DXXXX%26oauth_nonce%3DXXXX%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3DXXX%26oauth_token%3DXXXX%26oauth_version%3D1.0"). with Array ( [0] => 7992a0f54cc2104fec647c75a9aa8317 [1] => 1b1fea099c727b89d9c0cb9d9a618608 [2] => access ) -- Signature verification failed (HMAC-SHA1)

Am I missing something?


Solution

  • In fact the issue was on server side.

    The lib used signed the request without params if only one is present and with params if 2 or more are present.