java google api spreadsheet: Request had insufficient authentication scopes. - java

I set a spreadsheet handler for google-api in java like that:
private GoogleCredential getCredentials(InputStream secret) throws GeneralSecurityException,
IOException, URISyntaxException {
GoogleCredential credential;
if ( secret == null ) {
credential = GoogleCredential
.getApplicationDefault()
.createScoped(SheetsScopes.all());
} else {
credential = GoogleCredential
.fromStream(secret)
.createScoped(SheetsScopes.all());
}
return credential;
}
and
public static java.util.Set<String> all() {
java.util.Set<String> set = new java.util.HashSet<String>();
set.add(DRIVE);
set.add(DRIVE_FILE);
set.add(DRIVE_READONLY);
set.add(SPREADSHEETS);
set.add(SPREADSHEETS_READONLY);
return java.util.Collections.unmodifiableSet(set);
}
I try to run this code on appengine (java8) and i get an exception when i try to read from my spreadsheet (my appengine email is a editor for that spreadsheet)
com.google.apphosting.runtime.jetty9.JettyLogger warn: /
java.lang.RuntimeException: com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "global",
"message" : "Request had insufficient authentication scopes.",
"reason" : "forbidden"
} ],
"message" : "Request had insufficient authentication scopes.",
"status" : "PERMISSION_DENIED"
}
how can i debug or fix this?

Related

create a Credential with access_token/refresh_token/expires_in parameters without the flow/installApp stuff

The quick start sample project is loading the *.json credential file, do the authorization flow, save the tokens in another file, and then use the token to create a credential. My goal is to do them in separate steps:
store the tokens in a DB after the exchange the authorization code for tokens
retrieve the tokens from DB
check the credential expiry and refresh token if needed and save it to DB again
create a credential object (without doing the flow/authorizationInstalledApp stuff)
So I tried the following to create the credential with the token related pramameters:
TokenResponse tokens = new TokenResponse();
String token = "xxxxxxxxxxxxxxx$$$$$$$$$";
tokens.setAccessToken(token);
tokens.setTokenType("bearer");
tokens.setExpiresInSeconds(3500L);
Credential credential = new
Credential(BearerToken.authorizationHeaderAccessMethod()).setFromTokenResponse(tokens);
The credential was created but the API call failed with:
401 Unauthorized { "code" : 401, "errors" : [ {
"domain" : "global",
"location" : "Authorization",
"locationType" : "header",
"message" : "Invalid Credentials",
"reason" : "authError" } ], "message" : "Invalid Credentials" }
I also tried another suggestion in the java doc:
public static Credential createCredentialWithRefreshToken(
HttpTransport transport, JsonFactory jsonFactory, TokenResponse tokenResponse) {
return new Credential.Builder(BearerToken.authorizationHeaderAccessMethod()).setTransport(
transport)
.setJsonFactory(jsonFactory)
.setTokenServerUrl(
new GenericUrl("https://server.example.com/token"))
.setClientAuthentication(new BasicAuthentication("s6BhdRkqt3", "7Fjfp0ZBr1KtDRbnfVdmIw"))
.build()
.setFromTokenResponse(tokenResponse);
}
That also did not work for me. So my questions are:
can we just create a very simple credential object with access_token, refresh_token, expires?
why do we have to hook up with the GoogleAuthorizationCodeFlow?
what's the minimum required parameters for a valid credential object based on Java client library (OAuth 2.0).
Thanks a lot for any ideas/input.

ESTEASY003650: No resource method found for GET, return 405 with Allow header

I am trying to get a Token from the Intranet Server and in the process getting error
RESTEASY003650: No resource method found for GET, return 405 with Allow header
Using Java 11 API. I have already tried using postman and the client works like a charm but trying to do as a stand alone java application. This is the code in main application
try {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://myurl:8480/rest/v1/auth/token"))
.setHeader("client_id", "rest-client")
.setHeader("client_secret", "xxxxxxxxxxxxxxxxxxxx")
.setHeader("username", "user")
.setHeader("Content-Type","application/x-www-form-urlencoded")
.setHeader("password", "password")
.build();
client.sendAsync(request, BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join();
} catch (Exception e) {
System.out.println("MalformedURLException");
e.printStackTrace();
}
I should get a token in response. I am getting this error
{ "error" : {
"code" : "500",
"target" : "context",
"details" : [ {
"message" : "javax.ws.rs.NotAllowedException: RESTEASY003650: No resource method found for GET, return 405 with Allow header",
"code" : "NotAllowedException"
} ] }

How to implement Exponential Backoff for Google Gmail API?

I am currently using Gmail API to send emails on user's behalf. The Mails are sent one by one and the average size of recipients is 500.
I frequently see {
"code" : 500,
"errors" : [ {
"domain" : "global",
"message" : "Backend Error",
"reason" : "backendError"
} ],
"message" : "Backend Error"
}
as well as some occurrences of
{
"code" : 429,
"errors" : [ {
"domain" : "usageLimits",
"message" : "Rate Limit Exceeded",
"reason" : "rateLimitExceeded"
} ],
"message" : "Rate Limit Exceeded"
}
Google has suggested implementing Exponential backoff strategy to resolve these errors. I have implemented below solution, but it doesn't seem to work and is not helping with these errors.Here is my implementation;
public GoogleCredential createCredentialWithRefreshToken(String accessToken, String refreshToken)
{
GoogleCredential credential = new GoogleCredential.Builder().setTransport(new NetHttpTransport())
.setJsonFactory(new JacksonFactory())
.setClientSecrets(Constants.GOOGLE_CLIENT_ID, Constants.GOOGLE_CLIENT_SECRET)
.setRequestInitializer(setHttpTimeout())
.build();
credential.setAccessToken(accessToken).setRefreshToken(refreshToken);
return credential;
}
public HttpRequestInitializer setHttpTimeout() {
return new HttpRequestInitializer() {
#Override
public void initialize(HttpRequest httpRequest) throws IOException {
httpRequest.setUnsuccessfulResponseHandler(new HttpBackOffUnsuccessfulResponseHandler(backOff()));
httpRequest.setConnectTimeout(3 * 60000); // 3 minutes connect timeout
httpRequest.setReadTimeout(3 * 60000); // 3 minutes read timeout
}
private final ExponentialBackOff.Builder BACK_OFF = new ExponentialBackOff.Builder().setInitialIntervalMillis(500);
private BackOff backOff() {
return BACK_OFF.build();
}
};
}
public static Gmail getGmailServiceForGoogleAccount(GoogleAccount googleAcct){
Gmail gmailService = null;
GoogleCredential credential = new Utils().createCredentialWithRefreshToken(googleAcct.getAccess_token(),googleAcct.getRefresh_token());
gmailService = new Gmail.Builder(new NetHttpTransport(),
new JacksonFactory(), credential)
.setApplicationName("test")
.build();
return gmailService;
}
What is wrong with this implementation? Am i implementing the custom HttpRequestInitializer correctly.
Where could i set the log statements to find out if a request is being retried as per Exponential policy?
Please suggest
I see this is an old question, but will leave my answer here in case anyone finds it useful.
The problem with the code is that it is calling .setRequestInitializer() on the GoogleCredential.Builder, which sets the initializer for token requests and not the service API requests.
See the documentation here
Sets the HTTP request initializer for refresh token requests to the token server or null for none.
Instead the initializer should be configured on the Google service client and you can chain it with the Credential response handler to preserve its functionality too.
Something like this should work for the provided example:
public static HttpRequestInitializer requestInitializer(Credential credential) {
return new HttpRequestInitializer() {
#Override
public void initialize(HttpRequest httpRequest) throws IOException {
httpRequest.setConnectTimeout(3 * 60000); // 3 minutes connect timeout
httpRequest.setReadTimeout(3 * 60000); // 3 minutes read timeout
// chain response handler with the handler from the credential
// that handles retries for authentication errors
HttpUnsuccessfulResponseHandler responseHandler =
new HttpBackOffUnsuccessfulResponseHandler(backOff());
httpRequest.setUnsuccessfulResponseHandler((req, res, retry) ->
credential.handleResponse(req, res, retry)
|| responseHandler.handleResponse(req, res, retry));
}
private final ExponentialBackOff.Builder BACK_OFF = new ExponentialBackOff.Builder().setInitialIntervalMillis(500);
private BackOff backOff() {
return BACK_OFF.build();
}
};
}
public static Gmail getGmailServiceForGoogleAccount(GoogleAccount googleAcct){
GoogleCredential credential = new Utils().createCredentialWithRefreshToken(googleAcct.getAccess_token(),googleAcct.getRefresh_token());
return new Gmail.Builder(new NetHttpTransport(), new JacksonFactory(), requestInitializer(credential))
.setApplicationName("test")
.build();
}
Check the Exponential Backoff for Java implementation:
ExponentialBackOff backoff = new ExponentialBackOff.Builder()
.setInitialIntervalMillis(500)
.setMaxElapsedTimeMillis(900000)
.setMaxIntervalMillis(6000)
.setMultiplier(1.5)
.setRandomizationFactor(0.5)
.build();
request.setUnsuccessfulResponseHandler(new HttpBackOffUnsuccessfulResponseHandler(backoff));
Check this SO post for additional reference.

Google Cloud Storage JSON API Service account 403 Forbidden

I am trying to access Google Cloud Storage buckets objects with Java JSON API.
We are uses service account authentication. We also check our permission of service account ID as "Editor".
When we tried to list out bucket Object we got following error.
403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "global",
"message" : "Forbidden",
"reason" : "forbidden"
} ],
"message" : "Forbidden"
}
Authentication Code
HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = new JacksonFactory();
GoogleCredential credential = null;
InputStream credentialsStream = null;
try {
credentialsStream = new FileInputStream("<Location of Service Account JSON File>");
credential =GoogleCredential.fromStream(credentialsStream, transport, jsonFactory);
} catch (IOException e) {
} finally {
if (credentialsStream != null) {
credentialsStream.close();
}
}
if (credential.createScopedRequired()) {
Collection<String> scopes = StorageScopes.all();
credential = credential.createScoped(scopes);
}
return new Storage.Builder(transport, jsonFactory, credential)
.setApplicationName("DemoApplication")
.build();
Bucket Object Code
Storage client = StorageFactory.getService();
Storage.Objects.List listRequest = client.objects().list(bucketName);
List<StorageObject> results = new ArrayList<StorageObject>();
Objects objects;
// Iterate through each page of results, and add them to our results list.
do {
objects = listRequest.execute();
// Add the items in this page of results to the list we'll return.
results.addAll(objects.getItems());
// Get the next page, in the next iteration of this loop.
listRequest.setPageToken(objects.getNextPageToken());
} while (null != objects.getNextPageToken());
Please help me out for this issue.

AuthError On YouTube Search List Execute

I am exploring YouTube API and creating a java application which can search with authorized users token. I do Authorization as follows.
private static Credential authorize(String storeDirectory) throws Exception {
// load client secrets
YT.DATA_STORE_DIR = new java.io.File(".",".store/"+storeDirectory);
YT.dataStoreFactory = new FileDataStoreFactory(YT.DATA_STORE_DIR);
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(YT.JSON_FACTORY,
new InputStreamReader(new ByteArrayInputStream(YT.CLIENT_SECRET_JSON.getBytes(StandardCharsets.UTF_8))));
if (clientSecrets.getDetails().getClientId().startsWith("Enter")
|| clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) {
System.out.println(
"Enter Client ID and Secret from https://code.google.com/apis/console/?api=plus "
+ "into client string.");
System.exit(1);
}
String[] permissoins = { PlusScopes.PLUS_LOGIN, PlusScopes.PLUS_ME, PlusScopes.USERINFO_EMAIL, PlusScopes.USERINFO_PROFILE, "https://www.googleapis.com/auth/youtube" };
// set up authorization code flow
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
YT.httpTransport, YT.JSON_FACTORY, clientSecrets,
new ArrayList(Arrays.asList(permissoins))).setDataStoreFactory(
YT.dataStoreFactory).build();
// authorize
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
}
I am trying to search a single keyword as bellow
Credential credential = authorize("username");
YouTube.Search.List search = youtube.search().list("id,snippet");
// I have set OauthToken here.
search.setOauthToken(credential.getAccessToken());
search.setMaxResults(50L);
search.setQ("Search keyword");
search.setType("video");
search.setFields("items(id/kind,id/videoId,snippet/title,snippet/thumbnails/default/url)");
// It get exception below line.
SearchListResponse searchResponse = search.execute();
List<SearchResult> searchResultList = searchResponse.getItems();
I am getting exception details as below.
ex = (com.google.api.client.googleapis.json.GoogleJsonResponseException) com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized
{
"code" : 401,
"errors" : [ {
"domain" : "global",
"location" : "Authorization",
"locationType" : "header",
"message" : "Invalid Credentials",
"reason" : "authError"
} ],
"message" : "Invalid Credentials"
}
I am wondering i am missing to set any api key or I do something else wrong.
Do i need to use
search.setKey("YOUTUBE_DEVELOPER_KEY");
I am also confused what to use as YOUTUBE_DEVELOPER_KEY ?

Categories