I am making an android app which has a django rest api as the backend and want to make authenticated network calls using the token given to the user when he/she has logged in.
I am using retrofit to make requests to the backend. Here is what I am doing right now to attempt to make an authenticated network call to the rest api.
#Override
public void loadAllUsers() {
Call<List<User>> call = userServiceApi.loadAllUsers();
call.enqueue(new Callback<List<User>>() {
#Override
public void onResponse(#NonNull Call<List<User>> call, #NonNull Response<List<User>> response) {
if (response.isSuccessful()) {
List<User> users = response.body();
eventBus.post(new LoadAllUsersEvent(users));
} else {
eventBus.post(new FailLoadAllUsersEvent());
Log.d(TAG, response.message());
}
}
#Override
public void onFailure(#NonNull Call<List<User>> call, #NonNull Throwable t) {
eventBus.post(new LoadUsersUnreachableServerEvent());
Log.d(TAG, t.toString());
}
});
}
Here is the retrofit interface relevant to this api request:
#GET("users/")
Call<List<User>> loadAllUsers(#Header("Authorization: Token ") Token token);
When I make this call passing the user's token in as the header, I get status code 401: Unauthenticated: "GET /users/ HTTP/1.1" 401 58
What am I doing wrong for django rest Token Authentication to work and to make an authenticated django rest api call?
The quick fix for this would be to change your api interface:
#GET("users/")
Call<List<User>> loadAllUsers(#Header("Authorization") Token token);
Value you are passing in should be formated as "Token %s".
This is not a very good solution, because you'd have to pass the token around to all of your api calls.
Better way to solve your authorization issues is by using OkHttp client and implement authenticator, which takes care of everything for you.
OkHttp and Retrofit work together very well.
Related
I'm want to consume share point rest API service to call from Android previously i use to call share point web service through the graph API but while generating token from graph API its not support in below URL, does any one have any solution about this problem.
https://mysharepoint.sharepoint.com/sites/MySite/_api/web/lists/getbytitle('Announcements')/Items
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, MSGRAPH_URL,
parameters,new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
/* Successfully called graph, process data and send to UI */
Log.d(TAG, "Response: " + response.toString());
updateGraphUI(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "Error: " + error.toString());
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", "Bearer " + authResult.getAccessToken());
return headers;
}
};
Log.d(TAG, "Adding HTTP GET to Queue, Request: " + request.toString());
request.setRetryPolicy(new DefaultRetryPolicy(
3000,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
queue.add(request);
I already tried with MSAL library but its does not work with this token.
Update: i used to call graph api for janrating token but i got 401 error with this above mention URL.
You are calling a SharePoint API, so you will need a SharePoint token instead of a Graph token. These are two separate APIs with different authentications.
To get a SharePoint token you will need to register an App in SharePoint itself or use the users username + password if available in your app.
Also see:
https://spshell.blogspot.com/2015/03/sharepoint-online-o365-oauth.html
https://shareyourpoint.net/2017/01/25/operations-using-rest-in-sharepoint-online-authorization/
For Graph, use an URL like this to get your list items:
https://graph.microsoft.com/v1.0/sites/{site-id}/lists/{list-id}/items?expand=fields(select=Column1,Column2)
You will probably need to do several calls to get your site ID and list ID first.
https://learn.microsoft.com/en-us/graph/api/listitem-list?view=graph-rest-1.0
I want to create an app which will locate an Scooters. I am using Bird(Scooter) api. I got an Auth token, but when I want to send request with GET method, with headers, it returns me response code 401, but auth token is not null. Please help me. Api Documentation
My request interface
public interface ApiCallsInterface {
#Headers({
"Device-id:43ba174c-11f4-4918-9fcc-6d785cfc256e"
,"Platform:android","Content-type:application/json"
})
#POST("/user/login")
Call<AuthResponseClass> getAuthToken(#Body Map<String, String> params);
#Headers({
"Device-id:43ba174c-11f4-4918-9fcc-6d785cfc256e",
"App-Version:3.0.5"
})
#GET("/bird/nearby?latitude=37.77184&longitude=-122.40910&radius=1000")
Call<BirdResponse> getBirds(#Header("Authorization") String token, #Header("Location") Map<String, String> params);}
How I send request
Map<String, String> requestParams = new HashMap<>();
requestParams.put("latitude",lat);
requestParams.put("longitude",lng);
requestParams.put("altitude","500");
requestParams.put("accuracy","100");
requestParams.put("speed","-1");
requestParams.put("heading","-1");
apiCallsInterface.getBirds(AUTH_TOKEN,requestParams).enqueue(new Callback<BirdResponse>() {
#Override
public void onResponse(Call<BirdResponse> call, Response<BirdResponse> response) {
Log.d(TAG,"" + response.code());
}
#Override
public void onFailure(Call<BirdResponse> call, Throwable t) {
}
});
Be sure to append "Bird " before your token as in your api documentation.
401 The request requires user authentication
Not adding the header properly here is the guide to generate header properly
https://github.com/ubahnverleih/WoBike/blob/master/Bird.md
I am making use of Retrofit to call the restful webservices in the android, I have come across the scenario like I need to pass query params and request payload object in the retrofit request, so I've tried something like this
#POST("actual url")
Call<ReceiptList> getData(#Query("limit") String limit,
#Query("page") String page,
#Body ReceiptRequestPayload receiptRequestPayload);
Calling API
Call<cutomObject> responseCall = API.getData("10", "1", requestPayload);
responseCall .enqueue(new Callback<cutomObject>() {
#Override
public void onResponse(Call<cutomObject> call, retrofit2.Response<cutomObject> response) {
Log.d(TAG, "onResponse: Receipts"+response);
Log.d(TAG, "onResponse: Receipts"+response.body());
}
#Override
public void onFailure(Call<ReceiptList> call, Throwable t) {
}
});
But it's not working.
Thanks in advance
Use OkHttp Logging Interceptor to log your HTTP request and response data
I am attempting to get a user's Reddit front page. I have successfully received an Auth Token via the Token Retrieval (code flow). I have managed to get the expected JSON response via Postman, but cannot produce the same results with Retrofit. The request seems to be timing out as onFailure() is being triggered in the callback. I am using the scopes: identity, mysubreddits, and read.
Additional note: I have got a 401 and 403 response with the code below when using insufficient scopes and using an expired Auth Token respectively.
Relevant constants:
redditToken = (actual auth token String)
RedditConstants.REDDIT_BASE_URL_OAUTH2 = "https://oauth.reddit.com"
Relevant method Section:
if (redditToken != null) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(RedditConstants.REDDIT_BASE_URL_OAUTH2)
.addConverterFactory(GsonConverterFactory.create())
.build();
Api api = retrofit.create(Api.class);
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", "bearer " + redditToken);
headers.put("User-Agent", RedditConstants.REDDIT_USER_AGENT);
Call<RedditFeed> call = api.getFeed(headers);
call.enqueue(new Callback<RedditFeed>() {
#Override
public void onResponse(Call<RedditFeed> call, Response<RedditFeed> response) {
Log.d("FINDME", "response "+ response.toString());
if (response.isSuccessful()) {
Log.d("FINDME", "response was a success! we got the feed!");
} else {
Log.d("FINDME", "responce was not successfull triggered");
}
}
#Override
public void onFailure(Call<RedditFeed> call, Throwable t) {
Log.d("FINDME", "onFailure called from populateRedditFeed");
}
});
} else {
Toast.makeText(this, "Please Login with Reddit", Toast.LENGTH_SHORT).show();
}
Retrofit Interface:
public interface Api {
#GET(".")
Call<RedditFeed> getFeed (
#HeaderMap Map<String, String> headers
);
}
Log Results:
D/NetworkSecurityConfig: No Network Security Config specified, using
platform default
I/zygote: Do full code cache collection, code=123KB, data=105KB
After code cache collection, code=111KB, data=79KB
D/FINDME: onFailure called from populateRedditFeed
Postman Success:
After many starts and stops, seemingly randomly getting either a 200 or calling onFailure() I discovered the problem in one of my Retrofit model classes. The JSON response from Reddit contains a field that can either be a long or boolean. I had it defined as a boolean in my java class which threw an llegalStateException when it was returned as a long.
type name description
special edited false if not edited, edit date in UTC epoch-seconds
otherwise. NOTE: for some old edited comments on reddit.com, this will
be set to true instead of edit date.
*I'm unsure how to deal with this duality of types in java so for now I've commented out the field and the code works as expected.
The API I am working with gives completely different responses for success and failure.
Success:
{
"token":"asdfasdfhkAADBSKJBJBJKBJBK^%&BJBLLKHKJBXZ",
"email":"sample#sample.com",
"role":"admin"
}
Failure:
{
"name": "NotAuthenticated",
"message": "Invalid login.",
"code": 401,
"className": "not-authenticated"
}
I am very new to retrofit and am using the below code to make the call.
LoginRequest request = new LoginRequest(mobileNumber, password);
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
Call<LoginResponse> call = apiService.authenticateUser(request);
call.enqueue(new Callback<LoginResponse>() {
#Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
}
#Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
}
});
As you can see, retrofit forces me to use the Sample ResponseObject for both success and failure. And hence I am not able to convert the failure response to a pojo.
I have looked at custom deserialization. But writing a custom deserializer for each request can quickly go out of control.
Please help out.
I think the best solution for this will be getting Response Body form retrofit and Serializing it by our self in GSON . I am also looking for other sort of solution.