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 ?
Related
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.
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?
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.
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.
I tried many different things to access a google Account in order to read out profile-data, but it failed every time.
Exception in thread "main" 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 tried to access via following code
#SuppressWarnings("deprecation")
public static GoogleAccessProtectedResource connect(String CLIENT_ID,String CLIENT_SECRET,String SCOPE,String CALLBACK_URL,HttpTransport TRANSPORT,JsonFactory JSON_FACTORY) throws IOException{
// Generate the URL to which we will direct users
String authorizeUrl = new GoogleAuthorizationRequestUrl(CLIENT_ID,
CALLBACK_URL, SCOPE).build();
System.out.println("Paste this url in your browser: " + authorizeUrl);
// Wait for the authorization code
System.out.println("Type the code you received here: ");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String authorizationCode = in.readLine();
// Exchange for an access and refresh token
GoogleAuthorizationCodeGrant authRequest = new GoogleAuthorizationCodeGrant(TRANSPORT,
JSON_FACTORY, CLIENT_ID, CLIENT_SECRET, authorizationCode, CALLBACK_URL);
authRequest.useBasicAuthorization = false;
AccessTokenResponse authResponse = authRequest.execute();
String accessToken = authResponse.accessToken;
GoogleAccessProtectedResource access = new GoogleAccessProtectedResource(accessToken,
TRANSPORT, JSON_FACTORY, CLIENT_ID, CLIENT_SECRET, authResponse.refreshToken);
HttpRequestFactory rf = TRANSPORT.createRequestFactory(access);
System.out.println("Access token: " + authResponse.accessToken);
// Make an authenticated request
GenericUrl shortenEndpoint = new GenericUrl("https://www.googleapis.com/urlshortener/v1/url");
String requestBody =
"{\"longUrl\":\"http://farm6.static.flickr.com/5281/5686001474_e06f1587ff_o.jpg\"}";
HttpRequest request = rf.buildPostRequest(shortenEndpoint,
ByteArrayContent.fromString("application/json", requestBody));
HttpResponse shortUrl = request.execute();
BufferedReader output = new BufferedReader(new InputStreamReader(shortUrl.getContent()));
System.out.println("Shorten Response: ");
for (String line = output.readLine(); line != null; line = output.readLine()) {
System.out.println(line);
}
// Refresh a token (SHOULD ONLY BE DONE WHEN ACCESS TOKEN EXPIRES)
//access.refreshToken();
//System.out.println("Original Token: " + accessToken + " New Token: " + access.getAccessToken());
return access;
}
Then i want to access my account
public static void getData1(String accessToken, String clientId, String clientSecret, String refreshToken) throws IOException{
// Set up the HTTP transport and JSON factory
HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
// Set up OAuth 2.0 access of protected resources
// using the refresh and access tokens, automatically
// refreshing the access token when it expires
GoogleAccessProtectedResource requestInitializer =
new GoogleAccessProtectedResource(accessToken, httpTransport,
jsonFactory, clientId, clientSecret, refreshToken);
// Set up the main Google+ class
Plus plus = Plus.builder(httpTransport, jsonFactory)
.setHttpRequestInitializer(requestInitializer)
.build();
// Make a request to access your profile and display it to console
Person profile = plus.people().get("[myID]").execute();
System.out.println("ID: " + profile.getId());
System.out.println("Name: " + profile.getDisplayName());
System.out.println("Image URL: " + profile.getImage().getUrl());
System.out.println("Profile URL: " + profile.getUrl());
}
Following main method should work afterwards: CLIENT_ID and CLIENT_SECRET are created
public static void main(String[] args) throws IOException {
GoogleAccessProtectedResource access1=Connection.connect(CLIENT_ID, CLIENT_SECRET, SCOPE, CALLBACK_URL, TRANSPORT, JSON_FACTORY);
//refresh
String token= access1.getAccessToken();
access1.refreshToken();
String refreshed=access1.getAccessToken();
//get data
Connection.getData1(token, CLIENT_ID, CLIENT_SECRET, refreshed);
}
This is my Data...
private static final String SCOPE = "https://www.googleapis.com/auth/urlshortener";
private static final String CALLBACK_URL = "urn:ietf:wg:oauth:2.0:oob";
private static final HttpTransport TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
// FILL THESE IN WITH YOUR VALUES FROM THE API CONSOLE
private static final String CLIENT_ID = "[myID].apps.googleusercontent.com";
private static final String CLIENT_SECRET = "[myID]";
Now there is a bad Request Exception thrown
Exception in thread "main" com.google.api.client.http.HttpResponseException: 400 Bad Request
{
"error" : "invalid_client"
}
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:900)
at com.google.api.client.auth.oauth2.draft10.AccessTokenRequest.executeUnparsed(AccessTokenRequest.java:472)
at com.google.api.client.auth.oauth2.draft10.AccessTokenRequest.execute(AccessTokenRequest.java:486)
at Connection.connect(Connection.java:78)
at Connection.main(Connection.java:50)
This is hopefully pretty easy to fix.
You're using a SCOPE string of:
https://www.googleapis.com/auth/urlshortener
This is the scope for the URL Shortener (goo.gl) API, not the Google+ APIs. Instead you should probably try using the profile scope for Google+
https://www.googleapis.com/auth/plus.me
Documentation here:
https://developers.google.com/+/api/oauth
Above, it looks like you're using [myID] to reference two different types of ID:
In the below statement, the myID should be your Google+ profile ID (copied/pasted from the URL for your Google+ profile or instead use the string 'me' to represent the currently authorized user):
Person profile = plus.people().get("[myID]").execute();
However, for the CLIENT_ID, you should be using the values from your project in code.google.com/apis/console.