Android OAuth Retrofit Access Token Request - android

Can anyone tell the exact format to convert below code into retrofit
curl -X POST -d "grant_type=password&username=admin&password=admin&scope=read+write" -u"clientId:clientSecret" http://myserver/o/token/
I have tried something like this but it isn't working
#FormUrlEncoded
#POST("/o/token/")
AccessTokenResponse getToken(#Field("client_id") String client_id, #Field("client_secret") String client_secret,
#Field("grant_type") String grant_type, #Field("username") String username,
#Field("password") String password, #Field("scope") String scope);

Client credentials should be authenticated with Basic Authentication. i.e with header
Authorization: Basic base64encode(clientId:clientSecret)
where base64encode(clientId:clientSecret) is the actual base64 encoded string of clientId:clientSecret. So to update your interface it might look something more like
public interface OAuthTokenService {
#POST("/api/token")
#FormUrlEncoded
#Headers({
"Accept: application/json"
})
AccessTokenResponse getAccessToken(#Field("grant_type") String grantType,
#Field("username") String username,
#Field("password") String password,
#Header("Authorization") String authorization);
}
Then to set the header, do something like
public class Main {
public static void main(String[] args) {
RestAdapter restAdapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL)
.setEndpoint("http://localhost:8080")
.setConverter(new JacksonConverter())
.build();
OAuthTokenService service = restAdapter.create(OAuthTokenService.class);
byte[] credentials = "clientId:clientSecret".getBytes();
String basicAuth = "Basic " + Base64.getEncoder().encodeToString(credentials);
AccessTokenResponse response = service
.getAccessToken("password", "admin", "admin", basicAuth);
System.out.println(response.getAccessToken());
}
}
Note the above uses Java 8 for the java.util.Base64 class. You may not be using Java 8, in which case you will need to find a different encoder.
I am also using Jackson for conversion, only because I don't use Gson. The above has been tested and should work for you also.

With OkHttp interceptors this is made easier.
Interceptor interceptor = chain -> {
Request original = chain.request();
Request request = original.newBuilder()
.header("Authorization", Credentials.basic(CLIENT_ID, CLIENT_SECRET))
.method(original.method(), original.body())
.build();
return chain.proceed(request);
};
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.build();
return new Retrofit.Builder()
.baseUrl(baseURL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
The Credentials.basic method will base 64 encode your client id and client secret. The interceptor is then attached to the OkHttpClient client and added to the Retrofit object.

Related

Error 401 from retrofit even after setting the Authorization Token

Trying to access an api with #POST and I already set my #Header("Authorization") String TOKEN.
I've tried it with #GET and it worked, but I'm passing a some form fields so I need to use #POST
#POST("details")
#FormUrlEncoded
Call<Play> playTrack(
#Header("Authorization") String TOKEN,
#Field("event_id") int event_id,
#Field("longitude") double longitude,
#Field("latitude") double latitude
);
Try to create a header interceptor and add it to OkHttpClient :
Interceptor headerIntercepter = new Interceptor() {
#Override
public okhttp3.Response intercept(Chain chain) throws IOException {
return chain.proceed( chain.request().newBuilder().addHeader("authorization-
client", accessToken).build());
}
};
OkHttpClient client = new OkHttpClient.Builder().connectTimeout(120, TimeUnit.SECONDS).readTimeout(120, TimeUnit.SECONDS)
.addInterceptor(headerIntercepter)
.build();
try {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Server_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
apiService = retrofit.create(Api.class);
try using Multipart on annotation
#Multipart
#POST("details")
Call<ResponseBody> playTrack(
#Header("Authorization") String token,
#Part("event_id") RequestBody eventId,
#Part("longitude") RequestBody longitude,
#Part("latitude") RequestBody latitude,
);
make sure to pass a RequestBody as params
val latitude = RequestBody.create(MediaType.parse("text/plain"), doubleLatitude.toString())
Seeing a 401 response means that the request was successfully executed
and the server returned that status code. This is not a problem with
Retrofit, but in whatever authentication information you are including
in the request that the server expects.
Try with postman with the same data and check
N.B: Don't forgot to add Token Type as prefix to your token

Retrofit returns unknown characters [duplicate]

This question already has an answer here:
Retrofit encoding special characters
(1 answer)
Closed 3 years ago.
I'm having this weird error when using Retrofit.
First of all I tried using okhttpClient just for comparison and im getting the json result as expected.
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("email", "my.email#email.com")
.build()
val request = Request.Builder()
.url(BASE_URL + "account/forgot")
.post(requestBody)
.build()
var client = OkHttpClient()
client.newCall(request).execute()
.use { response ->
val response = response.body()!!.string()
}
Which returns
{"success": true, "email": "my.email#email.com", "uu_id": "000-0--0-0-000"}
Now Using the same logic, I tried converting it to retrofit but skip the GSON conversion as it returns unexpected error saying "JSON is not formatted"
so what I did was on callback, just return it as ResponseBody based on Retrofit's Documentation
#Headers("token: ", "accept-language: en-US", "accept: application/json", "accept-encoding: gzip, deflate, br", "Content-Type: application/json")
#POST("account/forgot")
fun resetPasswordDetails(#Body body:String): Call<ResponseBody>
And uses this RetrofitInstance
public static Retrofit getRetrofitInstance() {
Gson gson = new GsonBuilder()
.setLenient()
.create();
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient defaultHttpClient = new OkHttpClient.Builder()
.cookieJar(new JavaNetCookieJar(cookieManager))
.addInterceptor(loggingInterceptor)
.addInterceptor(new ResponseInterceptor())
.build();
if (retrofit == null) {
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(BASE_URL)
.client(defaultHttpClient)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
return retrofit;
}
on my Main activity I used it as
val service = RetrofitClientInstance.getRetrofitInstance().create(GetDataService::class.java)
val jsonBody = JSONObject()
jsonBody.put("email", "my.email#email.com")
val call = service.resetPasswordDetails(jsonBody.toString())
val response = call.execute()
val value = response.body()?.string()
I'm expecting the same result as what I did on okHttp but the return string was
���������������-�A
�0E�Rf)M1mc�+o"���)�ED�{��>��>PW"�.ݳ��w��Q����u�Ib�ȃd���x�/\r���#95s)�Eo���h�S����jbc���̚���� �������
Is there something wrong on my retrofit instance? Why is that it is working on okhttp but not on retrofit
EDIT:
My question is tagged as duplicate but I dont think thats the same question. While the other one states that the problem relates to URL encoding, My question is why is the okhttpclient and retrofit doesn't return the same JSON
Based on Xavier Rubio Jansana comment, I deleted some of my headers and now it is working properly. I just retain the #Headers("Content-Type: application/json").. Thanks a lot sir
It might be that you are sending the request as a JSON Body instead of Multipart like your OkHTTP request.
To make a Multipart request you can define your Retrofit request like this:
#POST("account/forgot")
fun resetPasswordDetails(#Part email:String): Call<ResponseBody>
Then you can just call the method with the email address without creating any JSONObject.

Retrofit with OkHTTP not set Content-Type with #FormUrlEncoded

I'm trying to implement auth via x-www-form-urlencoded with Retrofit 2 on Android but faced a problem, that Header Content-Type not set with #FormUrlEncoded annotation, as well as I'm trying to set it manually, but when I'm setting it with a typo like Cotent-Type it works correctly and I can see it in headers.
Retrofit version: 2.4.0
So my question: why #FormUrlEncoded not set a content type as well as #Header annotation or what can remove it from headers.
My request:
#FormUrlEncoded
#POST("account/login")
Single<LoginResponse> login(#Field("memberId") String memberId,
#Field("pin") String pin);
OkHTTP/Retrofit provider with interceptors:
#Singleton
#Provides
Retrofit provideRetrofit(final OkHttpClient client, final Moshi moshi) {
return new Retrofit.Builder()
.baseUrl(Configuration.BASE_URL)
.client(client)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
#Provides
OkHttpClient provideOkHttpClient(#AppContext final Context context) {
final OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
.followRedirects(true)
.followSslRedirects(true)
.addInterceptor(createLanguageInterceptor(context));
if (BuildConfig.DEBUG) {
builder.addInterceptor(new LoggingInterceptor());
}
return builder.build();
}
Interceptor createLanguageInterceptor(#AppContext final Context context) {
Locale current = context.getResources().getConfiguration().locale;
return chain -> {
Request.Builder builder = chain.request().newBuilder();
builder.addHeader("Accept-Language", current.getLanguage());
Request request = builder.build();
Response response = chain.proceed(request);
return response;
};
}
As a workaround, I've implemented the following interceptor:
Interceptor createHeaderTransformationInterceptor() {
return chain -> {
final Request request = chain.request();
String dataType = request.header("Data-Type");
final Request resultRequest = dataType == null
? request
: chain.request().newBuilder()
.removeHeader("Data-Type")
.addHeader("Content-Type", dataType)
.build();
return chain.proceed(resultRequest);
};
}
and it works fine with the following annotation:
#Headers({"Data-Type: application/x-www-form-urlencoded"})
UPD: the reason that my interceptor didn't see that is in a place where the content type is stored. The right way to see that header in an interceptor:
if (requestBody.contentType() != null) {
logger.log("Content-Type: " + requestBody.contentType());
}
if (requestBody.contentLength() != -1) {
logger.log("Content-Length: " + requestBody.contentLength());
}
By this Request
#FormUrlEncoded
#POST("account/login")
Single<LoginResponse> login(#Field("memberId") String memberId,
#Field("pin") String pin);
method #POST and #FormUrlEncoded automatic add
Content-Type: application/x-www-form-urlencoded in header you can check in log by
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(interceptor.setLevel(HttpLoggingInterceptor.Level.BODY))
.connectTimeout(2, TimeUnit.MINUTES)
.writeTimeout(2, TimeUnit.MINUTES)
.readTimeout(2, TimeUnit.MINUTES)
.build();
it print all log in verbose mode

Execute service with retrofit 2 sending data in header

I am learning to use retrofit, to consume Webservices, I have no problems in executing the #GET, #POST methods but now I have to execute a service where the token is sent, I really do not know how to do it, but I use POSTMAN where this field token I send from Headers in the Authorization key. I have seen other examples where OkHttpClient is used but I can not think of how to implement it.
So I execute my service with retrofit, to this same one the token in the head should be sent to him.
#GET(Constants.Retrofit.SURE_DO_YOU_LIKE_PRODUCTS)
Call<List<RelatedProducts>> getProductSureDoYouLike();
and this is my service in POSTMAN.
Like this:
#GET(Constants.Retrofit.SURE_DO_YOU_LIKE_PRODUCTS)
Call<List<RelatedProducts>> getProductSureDoYouLike(#Header("Content-Type") String contentType, #Header("Authorization") String auth);
If all requests require a Content-Type you could modify your Retrofit builder to include the header on every request:
OkHttpClient client;// = new OkHttpClient();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(5, TimeUnit.MINUTES)
.writeTimeout(5, TimeUnit.MINUTES)
.readTimeout(5, TimeUnit.MINUTES)
.addInterceptor(chain -> {
Request request = chain.request().newBuilder()
//Add this to include header in every request
.addHeader("Content-Type", "application/json").build();
return chain.proceed(request);
}).build();
client = builder.build();
retrofit = new Retrofit.Builder()
.baseUrl(NetworkConstants.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
Then your request would be:
#GET(Constants.Retrofit.SURE_DO_YOU_LIKE_PRODUCTS)
Call<List<RelatedProducts>> getProductSureDoYouLike(#Header("Authorization") String auth);
You would then call like so:
apiService.getProductSureDoYouLike("token");

Android Retrofit 2.0.0-beta2 Post string body dynamic headers

Retrofit 2.0.0-beta2
#Headers({
"Authorization: {authorization}",
"Content-Type: application/json"
})
#POST("/api/{id}/action/")
Call<String> postfn(#Header("Authorization") String authorization, #Path("id") String id, #Body String body);
i am using Gson converter
.addConverterFactory(GsonConverterFactory.create(gson))
i am getting error code=400, message=Bad Request Should i use a custom
converter?
Please help
You can't put this two things together.
There are two ways to put dynamic headers on requests with retrofit 2.0
1: put it only in method signature
#Headers({
"Content-Type: application/json"
})
#POST("/api/{id}/action/")
Call<String> postfn(#Header("Authorization") String authorization, #Path("id") String id, #Body String body);
2: using request interceptor to add fixed dynamic headers
public class TraktvApiProvider implements Provider<TraktvApi> {
public static final String BASE_URL = "https://api-v2launch.trakt.tv/";
#Override
public TraktvApi get() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(JacksonConverterFactory.create())
.build();
retrofit.client().interceptors().add(new LoggingInterceptor());
return retrofit.create(TraktvApi.class);
}
private class LoggingInterceptor implements Interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
request = request.newBuilder()
.addHeader("trakt-api-version", "2")
.addHeader("trakt-api-key", "[YOUR-API-KEY]")
.build();
Response response = chain.proceed(request);
String bodyString = response.body().string();
Log.d("Retrofit", "---------------------------------- REQUEST ----------------------------------");
Log.d("Retrofit", String.format("%s - %s", request.method(), request.url()));
Log.d("Retrofit", request.headers().toString());
Log.d("Retrofit", "---------------------------------- REQUEST ----------------------------------");
Log.d("Retrofit", "---------------------------------- RESPONSE ----------------------------------");
Log.d("Retrofit", response.headers().toString());
Log.d("Retrofit", "Body: " + bodyString);
Log.d("Retrofit", "---------------------------------- RESPONSE ----------------------------------");
return response.newBuilder()
.body(ResponseBody.create(response.body().contentType(), bodyString))
.build();
}
}
}
I moved back to the stable version 1.9 and intercepting worked fine.

Categories

Resources