Google Play Developer API - 400 Invalid Value - InAppPurchases - java

My question is similar to this one. However, I am using the API Java Client Library with a service account, making calls to the API from my server.
My code is following this guide, which is very simple. However, I can't seem to get an appropriate error for my request. This is how I build my AndroidPublisher:
val credential = GoogleCredential.fromStream(FileInputStream(
"/path/to/json"
)).createScoped(Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER))
androidPublisher = AndroidPublisher.Builder(httpTransport, JSON_FACTORY, credential)
.setApplicationName(packageName)
.build()
Where the JSON is generated from the Developer Console, under Service Accounts. This is how I make my request:
androidPublisher.purchases().subscriptions().get(packageName, "valid-sku", "invalid-token").execute()
My subscription ID is valid but my token is invalid. I expect an error such as "invalid token" in the response. However, what I get is:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
{
"code" : 400,
"errors" : [ {
"domain" : "global",
"message" : "Invalid Value",
"reason" : "invalid"
} ],
"message" : "Invalid Value"
}
Is that a generic error because of the invalid token or is it an authentication issue? If it an authentication issue, how do I solve it? If it is an invalid token issue, how am I supposed to know?
Some more information:
I get the same error when trying to make that call from the API Explorer as well (this time using a Client ID and API Key instead of Service Account).
I have not delegated domain-wide access to the service account. Do I have to for some reason?
I can successfully make other calls to the API such as inappproducts.list

From my experiences, if you have HTTP 400 error with Invalid Value then that purchase or subscription is FRAUD.
You can check out Order Id part of those purchases. Probably in the format of XXXXXXXXXXXX.XXXXXXXXXXXX which is wrong and should be GPA.XXXX.XXXXX.XXXXX.XXX
I don't really count the X char number. I just added to show the logic.

In my case the problem was that I was calling:
purchases.products.get
Instead of:
purchases.subscriptions.get

So, the reason that happened was just because the purchaseToken I was using was wrong.
I did not expect that to be the reason as I thought that in the case of an invalid token, I would receive a "token invalid" error (or something similar). As it turns out, the responses given by Google are pretty inconsistent (a 404 could also be given for an invalid token).

Scratched my head for a few hours, ALL my parameters were correct, and then well.. I realized that I was barking up the wrong tree (endpoint)
https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptions/{subscriptionId}/tokens/{token}
is not this
https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/products/{productId}/tokens/{token}
/purchases/subscriptions/.. vs /purchases/products/..

For all those who run into this problem, 99% of you need to publish the application for internal testers.
Follow this guide: https://support.google.com/googleplay/android-developer/answer/6062777?hl=en

Related

Google service account authorization error

I'm trying to use Google APIs with a service account.
Originally I used a normal project account with credentials and I managed to query the APIs. To use a service account, I modified the code to skip the browser auth flow and only use the service account credentials. It seems that the same request that used to work with the normal project credentials now give an error without clarifying much in the message. It goes as follows:
directoryService = new GoogleService().buildDirectoryService();
Users result = directoryService.users().list()
.setCustomer("my_customer")
.setOrderBy("email")
.execute();
public Directory buildDirectoryService() throws GeneralSecurityException, IOException {
final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
GoogleCredential credential = GoogleCredential
.fromStream(new FileInputStream("src/main/resources/newest_service_account_creds.json"))
.createScoped(SCOPES);
return new Directory.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName(APPLICATION_NAME)
.setHttpRequestInitializer(credential).build();
}
Unfortunately the error message is not saying much:
Exception in thread "main" com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
{
"code" : 400,
"errors" : [ {
"domain" : "global",
"message" : "Invalid Input",
"reason" : "invalid"
} ],
"message" : "Invalid Input"
}
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:146)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:321)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1108)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
at GetDrivePermissions.getFiles(GetDrivePermissions.java:35)
at Main.main(Main.java:7)
I repeated the process two times to make sure I didn't miss anything, including creating a new project, enabling the APIs, adding a service account, adding and enabling domain-wide delegation and obtaining a credentials json file, also adding access to the app in App Access Control in the admin UI. But calling
directoryService.users().list().setCustomer("my_customer").setOrderBy("email").execute();
service still returns the above error message.
The error message refers to "Invalid input", but the request used to work before, with normal application credentials. So the problem must lay not in how I call the Directory service but with my authentication, the only difference between the working and the non-working version.
Since this worked with using the project credentials, there must be something wrong with how I use the service account, but I can't find the error even after repeating the whole process two times. Based on the guides I found about service accounts, this is supposed to work. The credential object is created and it looks proper.
What can I look into next?
Thnaks for any insight in advance.
I changed this part back to use the application's own credentials. I have another call that uses the service account credentials and that works, so this is a workaround for now.

DocuSign Exception handling

I am using DocuSign Java SDK and trying to get access token using JWT flow.
When I call ApiClient.requestJWTUserToken I got error:
"POST https://account-d.docusign.com/oauth/token returned a response status of 400 Bad Request"
But when I set debugging true then I got the actual error message:
{
"error": "consent_required"
}
How can I get the real error?
You need to get consent first using the specified account.
This is a one time event using this URL:
https://account-d.docusign.com/oauth/auth?response_type=code&scope=signature%20impersonation&client_id={ClientID}&redirect_uri={Your URI}

Yelp android studio VALIDATION_ERROR

I am trying to integrate the YELP API within an application in Android Studio. I am trying to acquire an access token using a post request in Postman. However, when I send the post request I get this error returned in JSON format:
{
"error": {
"code": "VALIDATION_ERROR",
"description": "'client_credentials' is not one of ['authorization_code', 'refresh_token']",
"field": "grant_type",
"instance": "client_credentials"
}
}
I have searched this site and google for what the description line means in particular:
"description": "'client_credentials' is not one of ['authorization_code', 'refresh_token']",
I have not been able to find any results as to what this error means. Here is my project setup in postman:
I simply copy and pasted my client ID and API key from yelp and stored them within the client_id and client_secret in Postman respectively. When I send this requestion I get the 400 Bad Request error and find out that its a validation error. At first I thought that I entered the wrong API key, however, I refreshed the API key and directly copy and pasted it, so I am confident that my API key and client ID are correct. The output should look like this and it should deliver an access token:
I couldn't find any examples that had this specific error message.
You no longer need a refresh token, all you need is an API key in your Authorization header:
Authorization: Bearer {{apiKey}}
Source: https://www.yelp.com/developers/documentation/v3/authentication

Youtube API unexpected part on Update Message {0}

Been using the API for awhile now and have encountered a problem: A 400 Bad Request on "youtube.part" . Normally not a problem, I thought perhaps I have an inccorrect Part specified, the error message will tell me what is wrong and I can easily change it, however, the error is the following:
400 Bad Request
{
"code" : 400,
"errors" : [ {
"domain" : "youtube.part",
"location" : "part",
"locationType" : "parameter",
"message" : "{0}",
"reason" : "unexpectedPart"
} ],
"message" : "{0}"
}
Normally in the "message": "{0}" it should tell you what part is wrong. Having searched on here a bit, I can't seem to find a solution, right now I am only specifying snippet . In building my update request I am specifying only snippet.title snippet.tags[] & snippet.categoryId .
The above is used in a testing environment and the request is authorized with youtube scope, as I use it to upload the video just before to the same youtube channel.
My own Ideas are the it is perhaps:
Not possible to directly update a video, after loading it (however, it is possible to list)
That I have somehow encountered a bug
For those looking to recreate what I am getting, I took the following steps in my testing:
Set up a youtube instance using authorised credentials
Upload a random small file to the channel (setting video title etc.)
After a successful return attempt to list the video by id
Using this id, retrieve video resource from youtube
Alter the tags section, leaving the title etc unchanged
Attempt to update and receive that error
Any help would be appreciated and I really hope it isn't an obvious solution :)
This happens when your video update request doesn't list all the parts you are including in the video object you are sending. For example, if your video object has snippet and status (because you used video.setSnippet and video.setStatus), the first paremeter in the update method has to list both parts:
Video ve = listVids[0];
ve.setStatus(...)
ve.setSnippet(...)
...
YouTube.Videos.Update updateVideosRequest = youtube.videos().update("snippet, status", ve);
Video videoResponse = updateVideosRequest.execute();
Notice the first parameter of the youtube.videos().update, it has both status and snippet included.
Hope this can help you.

Google Drive service account returns 403 usageLimits

I'm trying to write an AppEngine app that writes a Google Document to Google Drive, puts in a specific set of folders and sets access rights. I have this working with the old DocsList API but since that just got deprecated I decided to update my code (and I had some additional functions to add anyway).
Problem I'm facing is this: When I use a service account and try to impersonate a specific user I get a 403 with usageLimits even though I have not used up any of my quota.
Here is the code I'm using:
GoogleCredential credentials = new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId("xxxxxxxxxxgserviceaccount.com")
.setServiceAccountScopes(DriveScopes.DRIVE)
.setServiceAccountPrivateKeyFromP12File(
new java.io.File("xxxx-privatekey.p12"))
.setServiceAccountUser("user#xxxxxx.org").build();
I than use these credentials to initiate my Drive object:
Drive d = Drive.builder(httpTransport, jsonFactory)
.setHttpRequestInitializer(credentials)
.setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() {
#Override
public void initialize(JsonHttpRequest request) {
DriveRequest driveRequest = (DriveRequest) request;
driveRequest.setPrettyPrint(true);
}
}).setApplicationName("MYAPPNAME").build();
BTW: I've tried using new Drive(....) but that just won't work, no matter what I try. Keeps throwing errors that internal methods are not found!
Back to this issue:
When I than use 'd' to call something like .files().get("SOMEFILEID").execute() I get a 403
{ "code" : 403,
"errors" : [ {
"domain" : "usageLimits",
"message" : "Daily Limit Exceeded. Please sign up",
"reason" : "dailyLimitExceededUnreg",
"extendedHelp" : "https://code.google.com/apis/console"
} ],
"message" : "Daily Limit Exceeded. Please sign up"
}
I can't figure out why this doesn't work. I've look online all day but can't find a suitable answer. Some help is very much appreciated.
So pinoyyid's answer did help, although it wasn't the definitive answer.
I ended up solving it like this:
I took my AppID (xxxxx.apps.googleusercontent.com) and added it to my CPanel https://www.google.com/a/cpanel/[[YOURDOMAIN]]/ManageOauthClients
with these scopes:
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/drive.file
https://www.googleapis.com/auth/userinfo.email
https://www.googleapis.com/auth/userinfo.profile
After that I had could do an authenticated request to the Drive environment. Running into a stack of different issues now but the 403 got solved.
I usually get a 403 when the API call was missing the Authorization http header. Trace the http and look at the headers. The rationale for the "quota" message is that without an Auth header, you are anonymous, and the quota for anonymous use is zero.
You might also check that your app is registered for both of the Drive APIs, as I've heard that that can cause the same problem.
On the internal method issue, that sounds like you're using incompatible library versions. What worked best for me was to delete all of the libraries I had downloaded with the sample code, then use the Google Eclipse plugin to "Google/Add Google APIs..." to download all of the latest versions.

Categories

Resources