Google Custom Search API - Engine Retrieving Engine Data Fails - google-api

I need to do CRUD on Custom Search Engines. From documentation, it looks pretty straight forward. I keep getting 401 responses though.
I am using Google.Apis.Oauth2.v2 to get a token:
String serviceAccountEmail = "blahblahblah#developer.gserviceaccount.com";
var certificate = new X509Certificate2(#"key.p12", "blah", X509KeyStorageFlags.Exportable);
var credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { "https://www.googleapis.com/auth/cse" }
}.FromCertificate(certificate));
bool result = credential.RequestAccessTokenAsync(CancellationToken.None).Result;
TokenResponse token = credential.Token;
I then add the token to the following request (Authorization: Bearer mytoken):
GET http://cse.google.com/api/<USER_ID>/cse/<CSE_ID>
There are a few things that jump at me.
Exact quote from documentation:
Although you can set HTTP requests to the URL http://cse.google.com/api/[USER_ID]/cse/[CSE_ID], we recommend using
the following URL instead:
http://cse.google.com/api/[USER_ID]/cse/[CSE_ID]
Note that both URL's are exactly the same.
In authentication section, the sample is using ClientLogin, which is deprecated. No samples with OAuth 2.0.
In the document's example, it says:
Each Custom Search engine is identified by a unique ID created by
combining a user ID with a Custom Search engine ID, separated by a
colon, like this:
011737558837375720776:mbfrjmyam1g In this case, the user ID is
011737558837375720776, and the search engine ID is mbfrjmyam.
You would have noticed that the search engine ID is 2 characters short of what it looks like should be.
Nowhere I have seen the scope as "https://www.googleapis.com/auth/cse". I just copied it from a stackoverflow post.
I understand this is a very long question, but I hope this will help the next person to look at this and consider these points.
Anyone knows why the 401s?

Related

How to run a query with Apollo GraphQL?

I am trying to figure out how to write a query in Apollo GraphQL.
I have a schema and have run the application in development mode. I have authenticated through the front end.
I expect that I should be able to follow this documentation and query the user.
I can see from the studio, that the Me query should be capable of checking for my first name (which I can see is recorded in the database), but when I press run in Apollo Studio, I get a null response to the query.
Is there an assumed step to get this working that needs to be taken before queries can be run? It gets worse when I try to do a query on the users table generally. That returns a not authenticated error (I have authenticated in the local environment in the dev app).
I'm struggling to connect the dots between the documentation that shows how this is expected to run queries and the starting point. I suspect that these documents have been prepared with the expectation that users know something fundamental about how to engage with them. I'm looking for disclosure as to what those assumptions might be. I can see from this question that there is a need for an authorisation header, (although my error is to do with authentication rather than authorisation). However, in my studio, the headers tab is empty. How do I populate it and what do I use to populate it?
I can see from the Apollo dev tool that it is trying to use a logged in query. I don't understand what drives this query in the Apollo Studio. Inside the localhost web app (which is running), I am logged in. When I try and run that query in the dev tools, the isLoggedIn (name of the query) is underlined, with an error explanation appearing that says:
Cannot query field "isLoggedIn" on type "Query".
The response shows:
{
"data": {}
}
I am lost for a starting point to find something to try and solve.
I think, based on a comment in this Odyssey tutorial, that the sandbox does not know how to connect to my psql data (not sure about this, but how could it know what queries I have, and not know which data has been stored in the attributes on the schema?). My env variables include my psql attributes and my prisma migrate is up to date. How can I let the sandbox know where the data is stored?
I am trying to learn using this boilerplate repo.
For my next attempt, I tried using the login mutation to generate a token, that I could try adding to the header. I don't know if it needs to be added under the name 'authorization' or 'token', so I made headers with both attribute names and added the same token to each of them.
I tried running the me and user query again, and get a mouthful of gibberish in the response.
The link in the response text goes to a page that has the following error message:
> <Error> <Code>NoSuchKey</Code> <Message>The specified key does not
> exist.</Message> </Error>
When I try going through the process of adding an APOLLO_KEY to my env variables and starting the server, I get an error that says "Unable to reach server". When I run the diagnose script on that error, I get:
Could not find any problems with the endpoint. Would you please to let
us know about this at explorer-feedback#apollographql.com 🙏
I created a new api key and tried again and am able to connect. I am able to run a login mutation and can return my first name inside that mutation, but I cannot do it from the me or user query - those queries still return the unauthenticated error response.
I have tried adding the authorization token to the header field both with and without "", and I have tried labelling that attribute as each of authorization, Authorization, token and then each of those inside "". None of them seems to make any difference to whether I can run a query. How can I find the name of the header token that Apollo Studio Explorer will accept?
I also tried the syntax suggested in this post, which is key Authorization and value "Bearer token" (there are double quotation marks around that string and a space between the word Bearer (capitalised) and the token string). There are no curly braces. That doesn't work either.
I have also tried expressing it as shown in this page of the Apollo documentation, which I think means that the key of the header value should be Authorization and the value should be the word Bearer, immediately followed by the token string generated in the output of the Login migration, inside {{ }}. When I try this, I get the same response as each of the other attempts described above.
There is a difference in the responses though, I get an unauthenticated response on the user query, and a null response on the me query.
One final strange observation: the studio returns the above error and null responses, but if I use the apollo client dev tools in the browser console, I can run the same Me query and get the result.
The user query still returns an unauthenticated error when I run it in the dev tools.
I'd also note that I can ask for the firstName attribute, inside the Login mutation, and receive them back in that response. However, I can't access them inside a Me query itself.
The next thing I investigated was how the resolver was managing the data. The boilerplate includes a resolver with:
import { AuthenticationError } from "apollo-server-express"
import { createMethodDecorator } from "type-graphql"
import { ResolverContext } from "../resolverContext"
export function UseAuth(roles?: string[]): any {
return createMethodDecorator<ResolverContext>(async ({ context: { req } }, next) => {
const argRoles = roles || []
if (req?.currentUser) {
if (argRoles.length === 0) return next()
if (argRoles.includes(req.currentUser.role)) return next()
throw new AuthenticationError("Not authorized")
} else {
throw new AuthenticationError("Not authenticated")
}
})
}
I wondered if maybe the role wasn't being considered. But I can see that it is inside the login mutation, but is not in a query.
Is there a 'for dummies' guide to getting started with apollo graphql?
I hope this spares someone some angst.
The format that works in Apollo Studio Explorer is
Key: Authorization
Value: Bearer[space][token]
There are no curly braces and no quotation marks in any of this. See this post for more discussion about this.

Calling Graph Api from Web Api doesn't return all user data

In my ASP.NET Core Web Api, I'm trying to call Graph API to retrieve the data of other users in the organization. I'm using the On Behalf Of flow. The bootstrap token is passed in from SPA client code.
In the Startup code, I have:
builder.Services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration)
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraph("https://graph.microsoft.com/beta", "user.read user.readbasic.all profile")
.AddInMemoryTokenCaches();
In the Controller's Action, I have:
_graphServiceClient.Users.Request()
.Filter($"mail eq 'someuser#myorg.com'")
.Select((user) => new {
DisplayName = user.DisplayName,
City = user.City,
Country = user.Country,
BusinessPhones = user.BusinessPhones
})
.Request()
.GetAsync();
However, at runtime, I only get the DisplayName value. I don't get the values of City, Country or BusinessPhones. They are al null.
When I tried the same query in Graph Explorer, I saw the values for all of them.
What am I missing?
First, your code snippet has an error that you wrote 2 .Request(), you should remove one.
Whatever flow you used are all generating an access token so that you can access the api, therefore when you got correct data from the api, that means you have a right setting in using the flow, so I think if there's any issue, it should locate at the part of calling api. Then I did some test in my side.
Could you pls check if you call the api directly, you can get the value of City, Country and BUsinessPhones these 3 properties? Per my test, when I call the api, I can get response like screenshot below and by default it's null
https://graph.microsoft.com/beta/users?$filter=mail eq
'tinywang#xxx.onmicrosoft.com'&$select=mail,city,country,DisplayName,BusinessPhones,userType,usageLocation
And when I followed this tutorial to call the api via sdk, I got the same result:
My idea is checking the response of calling the api first and if we can't find the issue, then could you pls provide the tutorial you followed to help reproduce the issue.

Unity WebGL/Parse Sign Up via REST API returns Unauthorized

I am working on integrating Parse with Unity for WebGL. Since the Parse plugin currently doesn't work with WebGL, I am forced to use the REST API (or edit the source code, which hasn't been working). Unfortunately, Parse doesn't have any documentation on how to use the REST API within the Unity/WebGL app, so I'm not even sure if I'm doing it right. Regardless, attempting to sign up with the code I posted below only gives me a "401 Unauthorized" error, at least in the Unity editor (I currently can't test to see if an actual build on my server will do anything different). I've also tried using the Client Key instead of the REST-API Key, but that had the same effect. Could someone give me pointers on where to go from here?
Here's my code:
string url = "https://api.parse.com/1/users";
WWWForm form = new WWWForm();
form.AddField("X-Parse-Application-Id", APP_ID);
form.AddField("X-Parse-REST-API-Key", REST_ID);
form.AddField("X-Parse-Revocable-Session", 1);
form.AddField("Content-Type", "application/json");
string newDataString = "{\"username\":\"" + email + "\",\"password\":\"" + password + "\",\"email\":\"" + email + "\"}";
WWW www = new WWW(url, System.Text.Encoding.UTF8.GetBytes(newDataString), form.headers);
The 401 error seems to point to a direction: the headers are not properly formatted. As an example, I was getting the same error because in the text field of an Authorization header there was a blank space between the = and " characters, like this:
token= "ajifidjoa...
So, first off, I suggest you to use something like Postman or any other REST client plugins for Chrome and test your call using them.
This way you should be able to understand better where the error is hidden.
Moreover, working with REST calls in Unity I found that a WebClient is way better for doing POST; sample code:
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/json";
result = client.UploadString(url, "POST", json_string_to_post);
}

How to search for users by ID and customData in Stormpath

I'm thinking about using Stormpath with it's Java API as a user storage.
Looks good, except that I can't search for users.
For example, I get this error:
Exception in thread "main" com.stormpath.sdk.resource.ResourceException: HTTP 400, Stormpath 2105 (http://docs.stormpath.com/errors/2105): Account ID is not a supported query property.
when I execute this query:
HashMap<String, Object> queryParams = Maps.newHashMap();
queryParams.put("ID", "4mPXXXXXXXXXX");
searchResult = application.getAccounts(queryParams);
Searching for a user by e-mail however works. I get the same error when I try to search a user by a login-token I stored in the customData property.
It looks like what I want to do is not possible as it looks like the only properties you can query are e-mail and username. But why would they provide this functionality if it didn't work. What am I missing?
There is an impedance mismatch between common relational database behaviors and those in a REST API. Querying by id, while common in relational databases, is not idiomatic behavior for REST APIs (or most HTTP-based web sites). The URL (href) is the canonical 'pointer' to a resource on the web. In other words, in REST APIs, the canonical identifier is the href. Any token inside an href (any internal 'id', special characters, whatever) should be opaque to REST clients and ignored by clients entirely. URLs are king in HTTP and REST.
That being the case, the Stormpath SDK tries to be true to RESTful best practices, so you can obtain any Stormpath resource by using the client.getResource method, which accepts an href and the type of object you expect that href to represent:
String href = "https://api.stormpath.com/v1/accounts/" + id;
Account account = client.getResource(href, Account.class);
That said, there's nothing wrong with wanting this to be more conveniently represented in the client API, for example, client.getAccount(String id) if you want to keep the notion of IDs. If so, please open a new feature request and we'll be very happy to consider it.
As for queryable Account properties, those are documented here. Stormpath will soon make data in Custom Data searchable as well. While Stormpath feature timelines are never announced, it is the company's highest engineering priority and it should be out soon.
One workaround that is helpful for some people is to store data they want to search in Account Fields that you don't use in your applications. For example, you could use the 'middle name' field to store, say, favorite color. This would only be temporary until custom data search is available. HTH!

Google API : Getting a Contacts Photo

I've been able to retrieve everything but the contacts photo by following the API.
I can get the img url as well as the gd:etag from the xml returned. Below is the Google API example, and it is the same thing I get, with the value of the attributes being different of course for my contacts.
<link rel='http://schemas.google.com/contacts/2008/rel#photo' type='image/*'
href='https://www.google.com/m8/feeds/photos/media/liz%40gmail.com/c9012de'
gd:etag='"KTlcZWs1bCp7ImBBPV43VUV4LXEZCXERZAc."'>
The problem is I don't know how to get it to display. When I try it, I just get the last part of the url (ie: "/32432eewqdweq") and no image.
I'm using rails, and this is my second week of doing web development, sorry if I seem noobish aha.
Any help would be appreciated!
Thanks,
Goran
You would need to make a request to the url, but also include the access_token as a query parameter.
So, using your example, let's say if your access_token is ABCDEF123456ABCDEF, then the GET request you want to make is:
https://www.google.com/m8/feeds/photos/media/liz%40gmail.com/c9012de?access_token=ABCDEF123456ABCDEF
Just a small hint, according to Google's API docs:
Note: If a contact does not have a photo, then the photo link element
has no gd:etag attribute.
More info here
First, you need to make a authorized GET to that url, i.e., in the Authorization header you have to put "OAuth " + AccessToken. Also, I haven't tried but, as Savil has said, with the Access Token as a Query Parameter, you can also achieve the same.
In any case, Google responds you with the bytes of the image, so you cannot display as is. You'll need either save the byte array to a file in your server (I don't think this to be a good solution) or find another way to display the photo
If you want to read more about it, here is Google's documentation about contact photos
This is a rather old question, but nevertheless I hope this can be helpful
Use the same authorized request code used for retrieving contacts and just replace the url with the link rel url of the contact image. Response will be the bytes of the image. Use the following code to return image as response.
//'in' is the inputStream returning from the call, response is the HttpServletResponse
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int read;
while (true) {
if ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
} else {
break;
}
}
response.setContentType("image/jpeg");
response.setContentLength(buffer.length);
request.getSession().setAttribute("image", new String(out.toByteArray()));
response.getOutputStream().write(buffer);

Resources