I am trying to implement OAuth2. I need to use it for my school project - the school provide some documentation and it say that I need to call this
POST /oauth/token HTTP/1.1
Host: oaas.example.org
Authorization: Basic ZHVtbXktY2xpZW50OnRvcC1zZWNyZXQ=
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=l1kSf2&redirect_uri=https://client.example.org/auth
or there is sample with curl
curl --data "grant_type=authorization_code&code=l1kSf2&redirect_uri=https://client.example.org/auth" \
--user dummy-client:top-secret https://oaas.example.org/oauth/token
But I dont know how to transfer it to Android calling. I am using Retrofit currently and reguest is like JSON :
POST /oauth/oauth/token/DeviceAndroid HTTP/1.1
Authorization: Basic OGRkOGJiZGMtOGI2NC00NTdlLTgwYWMtZmE5NDZjNzY4Njgzc0owY3RKV2VWNHFLY0dwWHNIOGEzcDVYYUl0NDRGN2o=
Content-Type: application/x-www-form-urlencoded
Content-Length: 85
Host: auth.fit.cvut.cz
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/2.5.0
{"code":"p1P3os","grant_type":"authorization_code","redirect_uri":"http://localhost"}
My network interface
public interface NetworkInterface {
String TAG = NetworkInterface.class.getName();
String URL = "https://auth.fit.cvut.cz";
#Headers("Content-Type: application/x-www-form-urlencoded")
#POST("/oauth/oauth/token/DeviceAndroid")
Call<Object> sendInformationToServer(#Body RequestToken requestToken);
}
RequestToken
public class RequestToken {
public static final String TAG = RequestToken.class.getName();
public String grant_type;
public String code;
public String redirect_uri;
...
Service generator
public class ServiceGenerator {
private static OkHttpClient httpClient = new OkHttpClient();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(NetworkInterface.URL)
.addConverterFactory(GsonConverterFactory.create());
public static <T> T createService(Class<T> serviceClass , final String autorizationString) {
httpClient = new OkHttpClient();
if (autorizationString != null) {
httpClient.interceptors().clear();
httpClient.interceptors().add(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.header("Content-Type", "application/x-www-form-urlencoded")
.header("Authorization", "Basic " + RequestToken.returnBase64(autorizationString))
.method(original.method(), original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
}
Retrofit retrofit = builder.client(httpClient).build();
return retrofit.create(serviceClass);
}
}
Is there a way to call it right with Retrofit (or with different approach), Thanks in advance
It seems like your call should look like the following
public interface NetworkInterface {
private String TAG = NetworkInterface.class.getName();
public statsic final String ROOT_URL = "https://auth.fit.cvut.cz";
#FormUrlEncoded
#POST("/oauth/token")
Call<Object> sendInformationToServer(
#Field("code") String code,
#Field("grant_type") String grant,
#Field("redirect_uri") String redirect,
);
}
Used like this:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(NetworkInterface.ROOT_URL)
...
.build();
NetworkInterface service = retrofit.create(NetworkInterface .class);
service.sendInformationToServer("p1P3os", "authorization_code", "http://localhost"})
Related
I am using retrofit to make a POST call to AWS server. It gives me the following error
Response{protocol=h2, code=403, message=, url=https://9oe8xt95sj.execute-api.ap-southeast-1.amazonaws.com/voip-dev-wa/staging/Device/registerCustomer}
My Retrofit method is as below
Retrofit retrofit;
retrofit = new Retrofit.Builder()
.baseUrl(ApiService.API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
apiService = retrofit.create(ApiService.class);
ApiService.java
String API_BASE_URL = "SOME String";
#POST("registerCustomer")
#Headers({"Content-Type: application/json", "accept: application/json"})
Call<RegisterResponse> register(#Body Register register);
How to solve this?
The problem is I did not pass the access token as the header. So it is responding forbidden error.
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.addInterceptor(new Interceptor() {
#Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request.Builder ongoing = chain.request().newBuilder();
ongoing.addHeader("Content-Type", "application/json");
ongoing.addHeader("accept", "application/json");
ongoing.addHeader("Authorization", "Bearer " + AppSetting.getInstance().getSDKDataManager().getAccessToken());
return chain.proceed(ongoing.build());
}
});
I try to receive token via POST json {"email":"test#example.com","password":"test"}. In postman it works:
Postman request.
I try do the same in Android Studio.
I create class Token:
public class Token {
#SerializedName("token")
#Expose
public String token;
}
And class APIclient
class APIClient {
private static Retrofit retrofit = null;
static Retrofit getClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
retrofit = new Retrofit.Builder()
.baseUrl("http://mybaseurl.com/")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
return retrofit;
}
}
and interface APIInterface:
interface APIInterface {
#POST("/authenticate")
Call<Token> getLoginResponse(#Body AuthenticationRequest request);
}
and class AuthenticationRequest:
public class AuthenticationRequest {
String email;
String password;
}
In onCreate in MainActivity:
apiInterface = APIClient.getClient().create(APIInterface.class);
authenticationRequest.email="test#example.com";
authenticationRequest.password="test";
getTokenResponse();
And here is my getTokenResponse method:
private void getTokenResponse() {
Call<Token> call2 = apiInterface.getLoginResponse(authenticationRequest);
call2.enqueue(new Callback<Token>() {
#Override
public void onResponse(Call<Token> call, Response<Token> response) {
Token token = response.body();
}
#Override
public void onFailure(Call<Token> call, Throwable t) {
call.cancel();
}
});
}
And this is what I see in Logcat:
03-15 10:53:56.579 20734-20756/com.retrofi2test D/OkHttp: --> POST http://mybaseurl.com/authenticate http/1.1
03-15 10:53:56.579 20734-20756/com.retrofi2test D/OkHttp: Content-Type: application/json; charset=UTF-8
03-15 10:53:56.579 20734-20756/com.retrofi2test D/OkHttp: Content-Length: 46
03-15 10:53:56.579 20734-20756/com.retrofi2test D/OkHttp: {"email":"test#example.com","password":"test"}
03-15 10:53:56.579 20734-20756/com.retrofi2test D/OkHttp: --> END POST (46-byte body)
Could you tell me what I'm doing wrong? I need to give token every time when I'd like to get information from server via GET method.
How can I receive and save token in Android code?
Try this
interface APIInterface {
#POST("/authenticate")
Call<Token> getLoginResponse(#Header("Authorization") String token, #Body AuthenticationRequest request);
}
token is the Bearer token
you should add application/json to header
interface APIInterface {
#Headers({"Content-Type: application/json", "Accept: application/json"})
#POST("/authenticate")
Call<Token> getLoginResponse(#Body AuthenticationRequest request);
}
To get access token from you need to get header from response and read values from headers.
Callback<User> user = new Callback<User>() {
#Override
public void success(User user, Response response) {
List<Header> headerList = response.getHeaders();
//iterating list of header and printing key/value.
for(Header header : headerList) {
Log.d(TAG, header.getName() + " " + header.getValue());
}
}
}
After you get the value you need from header i.e. AccessToken, you can store that value in Storage. e.g. SharedPreference
So next time when you need that value you can directly get that from Storage. e.g. SharedPreference
Now when you pass request for any webservice either that is GET or POST or any other method. You have to pass that into header requests.
#GET("/tasks")
Call<List<Task>> getTasks(#Header("Content-Range") String contentRange);
Or If you need to pass it every time, you can directly pass that from your Retrofit class.
Request request = original.newBuilder()
.header("User-Agent", "Your-App-Name")
.header("Accept", "application/vnd.yourapi.v1.full+json")
.method(original.method(), original.body())
.build();
I am using Retrofit in an Android application. When I hit an API with token to get user information it gives cached(previous) response. Whenever I logged out and log in again API gives previous user detail, I tested API in Postman it works fine there.
I have tried some solutions I searched but nothing is working.
Response header that I am getting is
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Kestrel
Date: Mon, 08 Jan 2018 09:35:26 GMT
Below is ApiClient class
public class ApiClient {
public static final String BASE_URL = "http://XX.XXX.XXX.XX/api/";
private static Retrofit authRetrofit = null;
private static Retrofit retrofit = null;
public static Retrofit getClient() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.build();
}
return retrofit;
}
public static Retrofit getAuthorizeClient(final String token) {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.addHeader("Authorization", "Bearer " + token)
.addHeader("Cache-control", "no-cache")
.method(original.method(), original.body())
//.cacheControl(CacheControl.FORCE_NETWORK)
.build();
return chain.proceed(request);
}
});
OkHttpClient client = httpClient.cache(null).build();
if (authRetrofit == null) {
authRetrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.client(client).build();
}
return authRetrofit;
}
}
In your httpClient interceptor, try adding cache control header:
.addHeader("Cache-control", "no-cache");
EDIT
Just noticed you are on Retrofit2
original.newBuilder().header("Cache-control", "no-cache");
Alternatively try adding it as an annotation to your API method:
#Headers("Cache-control: no-cache")
Response callApi();
According to Docs.
EDIT 2
Okay I suspect it's because of your if condition, your authRetrofit wouldn't be updated if condition failed. Try removing it
if (authRetrofit == null)
Help this helps.
Use Post request instead, I've faced the same problem, rectified by changing my GET method to post and send one random string as a Field.
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.
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.