React Native Facebook API batch requests - facebook-graph-api

I'm struggling with the batch request to the Facebook API in React Native. For a single request this tutorial works fine : https://github.com/facebook/react-native-fbsdk.
But can I create a batch request. Using GraphRequestBatch does not seem to work. Adding up request with addRequest() neither (such as suggested in https://github.com/facebook/react-native-fbsdk/issues/185).
Please help! I would like to send a batch of request with the same node and same edges, excepts only the time span changes.
Each request will look like :
const request = new GraphRequest('me/',
{
accessToken: accessToken,
parameters: {
fields: {
string: 'posts.since(t1).until(t2).limit(n){likes.summary(true)}'
}
}
},
responseInfoCallback);
I tried creating several requests, each with a different t1 and t2, then add them up like this :
const graphmanager = new GraphRequestManager().addRequest(requesta);
graphmanager.addRequest(requestb);
...
graphmanager.start();
But only the first request gets executed.
Thanks for the help!

Related

Axios Authorization not working - VueJS + Django

I am trying to build an application using VueJS and Django. I am also using Graphene-Django library, as the project utilize GraphQL.
Now, The authentication works fine and i get a JWT Token back.
But when i use the token for other queries that need authentication, i got this error in Vue:
"Error decoding signature"
and the Django Log also returns this:
graphql.error.located_error.GraphQLLocatedError: Error decoding signature
jwt.exceptions.DecodeError: Not enough segments
ValueError: not enough values to unpack (expected 2, got 1)
the bizarre thing is that the same query when executed in Postman just works fine.
As i mentioned in the title is use Axios for my requests, here's an example of a request:
axios({
method: "POST",
headers: { Authorization: "JWT " + localStorage.getItem("token") },
data: {
query: `{
dailyAppoint (today: "${today}") {
id
dateTime
}
}`
}
});
Note: It uses 'JWT' not 'Bearer' because somehow 'Bearer' didn't work for me.
Ok, couple of questions, does you API work without Vue.js from curl. Generate token, check API from curl.
If it does, then check the Headers sent from the request, from Network Inspector, mozilla dev tools/chrome devtools. And update your Post with those RAW Headers.
This particular error arises when your public key is unable to decode the string[token] signed by your private key. Which ultimately means the access token has been tampered with. It could also mean you're sending values like 'unkown'-- JS state initialization error.
Check the RAW headers of the request. It'll help.
Use a request interceptor to set the Authorization header:
axios.interceptors.request.use(config => {
if (localStorage.getItem("token") != null)
config.headers["Authorization"] = "JWT " + localStorage.getItem("token");
return config;
});

Get public events from Facebook Graph API via Android SDK

I'm trying to get public events from Facebook Graph API with the following code:
val request = GraphRequest.newGraphPathRequest(
AccessToken.getCurrentAccessToken(),
"/search",
GraphRequest.Callback { response : GraphResponse ->
Log.e("E", response.toString())
}
)
val parameters = Bundle()
parameters.putString("q", "Toronto")
parameters.putString("fields", "city,state,country,description,id,start_time,end_time,name,place,street,zip")
parameters.putString("type", "event")
parameters.putString("limit", "25000")
request.parameteans = parameters
request.executeAsync()
But I'm getting an empty data array. When I change the "type" field from "event" to "place" then I actually get the data.
Why am I getting no data for the event?
https://developers.facebook.com/docs/graph-api/changelog/breaking-changes#search-4-4
You can no longer use the /search endpoint with the following object
types:
event
group
page
user

ASP.Net Core 2.0 API Response hangs with large json payload

I am working on an ASP Net Core 2.0 Web API. One of my endpoints returns a json object that includes a text field that can be fairly large. When this field gets around 10Mb in size the controller just stops until the timeout is hit. When I debug, I see that the json object is created in my business logic and passed to the endpoint controller but the controller just stops right after it receives json object with no error and doesn't return to the caller until the request finally times out. I increased my requestTimeout to 20 mins even though the business logic generates the json object in less than 2 minutes. It just hangs until the 20 minute timeout is hit.
Here is my controller action;
[EXAMPLE 1]
[HttpGet(Name = "GetFile")]
public async Task<FileResponseDto> GetFile([FromRoute] int companyId, [FromRoute] int siteId, [FromRoute] int FileId,
[FromHeader(Name = "Accept")] string mediaType, CancellationToken cancellationToken)
{
var fileResponseDto = _fileBll.GetFile(companyId, siteId, fileId, HttpContext);
// This is the point where the controller appears to hang
return await Task.Factory.StartNew(() => fileResponseDto, cancellationToken);
}
and my DTO object;
public class FileResponseDto
{
public string ReferenceId { get; set; }
public string Filename { get; set; }
public string ProcessingFile { get; set; }
}
The property that is the large string is the ProcessingFile property in the FileResponseDto class.
This works fine until my ProcessingFile property gets to around 30K lines (about 10Mb) and then the controller just hangs after it completes the line;
var fileResponseDto = _fileBll.GetFile(companyId, siteId, fileId, HttpContext);
At this point, my assumption was that I have hit some limitation in the size of the json object. So, to test, I changed my controller so that it returns a file instead, like what is shown below;
[EXAMPLE 2]
[HttpGet(Name = "GetFile")]
public async Task<FileContentResults> GetFile([FromRoute] int companyId, [FromRoute] int siteId, [FromRoute] int fileId,
[FromHeader(Name = "Accept")] string mediaType, CancellationToken cancellationToken)
{
var fileResponseDto = _fileBll.GetFile(companyId, siteId, fileId, HttpContext);
var outputFile = Encoding.ASCII.GetBytes(fileResponseDto.ProcessingFile);
return await Task.Factory.StartNew(() =>
new FileContentResult(outputFile, new MediaTypeHeaderValue(MediaTypeNames.Application.Octet))
{
FileDownloadName = fileResponseDto.Filename
}, cancellationToken);
}
Making this change works and I can receive a file download dialog popup and a successful file if I select "Send and Download" in Postman.
So, this leads me to believe that there is something size related to the json object being transferred in the first example.
However, web searches have not turned up anything useful on this issue, which makes me think that perhaps I am missing something here.
I did find this link in StackOverflow and tried it by using...
var outfileJson = JsonConvert.SerializeObject<fileResponseDto>;
outfileJson.MaxJsonLength = Int32.MaxValue;
but outfileJson did not have a MasJsonLength property.
So.. any ideas?
EDIT 6/8/18
After 2 days, 22 views and no actual responses. I figured something must be wrong with my approach. I realized that I did not mention that I was performing these tests in Postman, which is where I was seeing the problem. After further digging, I found a post on GitHub that seemed to be related to what I was experiencing in Postman (the hang on large response payload). It seems that Postman has a limit in the number of "rows" it returns in the response. The GitHub post was a feature request to increase the number of rows.
I am not sure how to handle this StackOverflow question now. Since I didn't mention Postman in the original post, I don't feel right just answering my own question. So, I guess I will leave it as is for a couple of days to see if anyone chimes in with their thoughts before I do that.
As it turns out, the was, if fact, an issue with Postman and the size of the response payload it currently supports. If, instead of selecting Send, I select Send and Download in Postman, It will download the JSON object and pop up a dialog box to allow me to save it to my local drive. Then when I examine the file, I can see the json object is correctly formatted and transferred.
I confirmed that it was only a Postman issue and not a .NET HttpResponse issue by performing the API call in a .Net client application, which was able to receive the Json object without error.

Identity Server 3 Facebook Login Get Email

Identity server is implemented and working well. Google login is working and is returning several claims including email.
Facebook login is working, and my app is live and requests email permissions when a new user logs in.
The problem is that I can't get the email back from the oauth endpoint and I can't seem to find the access_token to manually request user information. All I have is a "code" returned from the facebook login endpoint.
Here's the IdentityServer setup.
var fb = new FacebookAuthenticationOptions
{
AuthenticationType = "Facebook",
SignInAsAuthenticationType = signInAsType,
AppId = ConfigurationManager.AppSettings["Facebook:AppId"],
AppSecret = ConfigurationManager.AppSettings["Facebook:AppSecret"]
};
fb.Scope.Add("email");
app.UseFacebookAuthentication(fb);
Then of course I've customized the AuthenticateLocalAsync method, but the claims I'm receiving only include name. No email claim.
Digging through the source code for identity server, I realized that there are some claims things happening to transform facebook claims, so I extended that class to debug into it and see if it was stripping out any claims, which it's not.
I also watched the http calls with fiddler, and I only see the following (apologies as code formatting doesn't work very good on urls. I tried to format the querystring params one their own lines but it didn't take)
(facebook.com)
/dialog/oauth
?response_type=code
&client_id=xxx
&redirect_uri=https%3A%2F%2Fidentity.[site].com%2Fid%2Fsignin-facebook
&scope=email
&state=xxx
(facebook.com)
/login.php
?skip_api_login=1
&api_key=xxx
&signed_next=1
&next=https%3A%2F%2Fwww.facebook.com%2Fv2.7%2Fdialog%2Foauth%3Fredirect_uri%3Dhttps%253A%252F%252Fidentity.[site].com%252Fid%252Fsignin-facebook%26state%3Dxxx%26scope%3Demail%26response_type%3Dcode%26client_id%3Dxxx%26ret%3Dlogin%26logger_id%3Dxxx&cancel_url=https%3A%2F%2Fidentity.[site].com%2Fid%2Fsignin-facebook%3Ferror%3Daccess_denied%26error_code%3D200%26error_description%3DPermissions%2Berror%26error_reason%3Duser_denied%26state%3Dxxx%23_%3D_
&display=page
&locale=en_US
&logger_id=xxx
(facebook.com)
POST /cookie/consent/?pv=1&dpr=1 HTTP/1.1
(facebook.com)
/login.php
?login_attempt=1
&next=https%3A%2F%2Fwww.facebook.com%2Fv2.7%2Fdialog%2Foauth%3Fredirect_uri%3Dhttps%253A%252F%252Fidentity.[site].com%252Fid%252Fsignin-facebook%26state%3Dxxx%26scope%3Demail%26response_type%3Dcode%26client_id%3Dxxx%26ret%3Dlogin%26logger_id%3Dxxx
&lwv=100
(facebook.com)
/v2.7/dialog/oauth
?redirect_uri=https%3A%2F%2Fidentity.[site].com%2Fid%2Fsignin-facebook
&state=xxx
&scope=email
&response_type=code
&client_id=xxx
&ret=login
&logger_id=xxx
&hash=xxx
(identity server)
/id/signin-facebook
?code=xxx
&state=xxx
I saw the code parameter on that last call and thought that maybe I could use the code there to get the access_token from the facebook API https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow
However when I tried that I get a message from the API telling me the code has already been used.
I also tried to change the UserInformationEndpoint to the FacebookAuthenticationOptions to force it to ask for the email by appending ?fields=email to the end of the default endpoint location, but that causes identity server to spit out the error "There was an error logging into the external provider. The error message is: access_denied".
I might be able to fix this all if I can change the middleware to send the request with response_type=id_token but I can't figure out how to do that or how to extract that access token when it gets returned in the first place to be able to use the Facebook C# sdk.
So I guess any help or direction at all would be awesome. I've spent countless hours researching and trying to solve the problem. All I need to do is get the email address of the logged-in user via IdentityServer3. Doesn't sound so hard and yet I'm stuck.
I finally figured this out. The answer has something to do with Mitra's comments although neither of those answers quite seemed to fit the bill, so I'm putting another one here. First, you need to request the access_token, not code (authorization code) from Facebook's Authentication endpoint. To do that, set it up like this
var fb = new FacebookAuthenticationOptions
{
AuthenticationType = "Facebook",
SignInAsAuthenticationType = signInAsType,
AppId = ConfigurationManager.AppSettings["Facebook:AppId"],
AppSecret = ConfigurationManager.AppSettings["Facebook:AppSecret"],
Provider = new FacebookAuthenticationProvider()
{
OnAuthenticated = (context) =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:access_token", context.AccessToken, ClaimValueTypes.String, "Facebook"));
return Task.FromResult(0);
}
}
};
fb.Scope.Add("email");
app.UseFacebookAuthentication(fb);
Then, you need to catch the response once it's logged in. I'm using the following file from the IdentityServer3 Samples Repository, which overrides (read, provides functionality) for the methods necessary to log a user in from external sites. From this response, I'm using the C# Facebook SDK with the newly returned access_token claim in the ExternalAuthenticationContext to request the fields I need and add them to the list of claims. Then I can use that information to create/log in the user.
public override async Task AuthenticateExternalAsync(ExternalAuthenticationContext ctx)
{
var externalUser = ctx.ExternalIdentity;
var claimsList = ctx.ExternalIdentity.Claims.ToList();
if (externalUser.Provider == "Facebook")
{
var extraClaims = GetAdditionalFacebookClaims(externalUser.Claims.First(claim => claim.Type == "urn:facebook:access_token"));
claimsList.Add(new Claim("email", extraClaims.First(k => k.Key == "email").Value.ToString()));
claimsList.Add(new Claim("given_name", extraClaims.First(k => k.Key == "first_name").Value.ToString()));
claimsList.Add(new Claim("family_name", extraClaims.First(k => k.Key == "last_name").Value.ToString()));
}
if (externalUser == null)
{
throw new ArgumentNullException("externalUser");
}
var user = await userManager.FindAsync(new Microsoft.AspNet.Identity.UserLoginInfo(externalUser.Provider, externalUser.ProviderId));
if (user == null)
{
ctx.AuthenticateResult = await ProcessNewExternalAccountAsync(externalUser.Provider, externalUser.ProviderId, claimsList);
}
else
{
ctx.AuthenticateResult = await ProcessExistingExternalAccountAsync(user.Id, externalUser.Provider, externalUser.ProviderId, claimsList);
}
}
And that's it! If you have any suggestions for simplifying this process, please let me know. I was going to modify this code to do perform the call to the API from FacebookAuthenticationOptions, but the Events property no longer exists apparently.
Edit: the GetAdditionalFacebookClaims method is simply a method that creates a new FacebookClient given the access token that was pulled out and queries the Facebook API for the other user claims you need. For example, my method looks like this:
protected static JsonObject GetAdditionalFacebookClaims(Claim accessToken)
{
var fb = new FacebookClient(accessToken.Value);
return fb.Get("me", new {fields = new[] {"email", "first_name", "last_name"}}) as JsonObject;
}

Google Apps Script and cookies

I am trying to Post and get a cookie. I am a newbie and this is a learning project for me. My impression is that if you use 'set-cookie' one should be able to see an additional 'set-cookie' in the .toSource. (I am trying to accomplish this on Google Apps Site if that makes a difference.) Am I missing something? Here is my code:
function setGetCookies() {
var payload = {'set-cookie' : 'test'};
var opt2 = {'headers':payload, "method":"post"};
UrlFetchApp.fetch("https://sites.google.com/a/example.com/blacksmith", opt2);
var response = UrlFetchApp.fetch("https://sites.google.com/a/example.com/blacksmith")
var openId = response.getAllHeaders().toSource();
Logger.log(openId)
var AllHeaders = response.getAllHeaders();
for (var prop in AllHeaders) {
if (prop.toLowerCase() == "set-cookie") {
// if there's only one cookie, convert it into an array:
var myArray = [];
if ( Array.isArray(AllHeaders[prop]) ) {
myArray=AllHeaders[prop];
} else {
myArray[0]=AllHeaders[prop];
}
// now process the cookies
myArray.forEach(function(cookie) {
Logger.log(cookie);
});
break;
}
}
}
Thanks in advance! I referenced this to develop the code: Cookie handling in Google Apps Script - How to send cookies in header?
Open to any advice.
When you aren't logged in Google Sites won't set any cookies in the response. UrlFetchApp doesn't pass along your Google cookies, so it will behave as if you are logged out.
First the cookie you want to send whose name is 'test' does not have a value. You should send 'test=somevalue'.
Second I am wondering if you are trying to send the cookie to the googlesite server and ask it to reply with the same cookie you previously sent... ?
I am thinking you are trying to act as a HTTP server beside you are a HTTP client.
As a HTTP client your role is only to send back any cookies that the HTTP server have previously sent to you (respecting the domain, expiration... params).