Google authentication from server - java

I am need to upload video to youtube to specific youtube account. So I need to authenticate I am using java google lib. Code looks like this:
Credential credential = new GoogleCredential.Builder()
.setTransport(new ApacheHttpTransport())
.setJsonFactory(new JacksonFactory())
.setServiceAccountId("xxx#xx-app.iam.gserviceaccount.com")
.setClientSecrets("xx#gmail.com", "xx")
.setServiceAccountPrivateKeyFromP12File(new File("xx.p12"))
.setServiceAccountScopes(scopes)
.setServiceAccountUser("xx#gmail.com")
.build();
youtube = new YouTube.Builder(credential.getTransport(), credential.getJsonFactory(), credential).setApplicationName(
"tellews-app").build();
Video returnedVideo = videoInsert.execute();
YouTube.Videos.Insert videoInsert = youtube.videos()
.insert("snippet,statistics,status", videoObjectDefiningMetadata, mediaContent);
Video returnedVideo = videoInsert.execute();
And getting error:
IOException: 401 Unauthorized
{
"error" : "unauthorized_client",
"error_description" : "Client is unauthorized to retrieve access tokens using this method."
}
Maybe someone sees what I am doing wrong

Simple.
Do not use a Service Account - that's not what they're there for.
You need to obtain an Access Token for the target YouTube account. The simples way to do that is to get yourself a Refresh Token for that account from the Oauth Playground, and use it to fetch an Access Token whenever you need one. The steps to do this are enumerated at How do I authorise an app (web or installed) without user intervention? (canonical ?) . In the comments there is a link to a YouTube video which also explains the steps.

Related

Access google photos API via Java

I am very new to google API and I am having troubles with it. I red documentation Google photos API for Java, then I created OAuth credentials in google API console and downloaded it (credentials.json file).
After that I tried to access google photos. Here is code from documentation:
// Set up the Photos Library Client that interacts with the API
PhotosLibrarySettings settings =
PhotosLibrarySettings.newBuilder()
.setCredentialsProvider(
FixedCredentialsProvider.create(/* Add credentials here. */))
.build();
try (PhotosLibraryClient photosLibraryClient =
PhotosLibraryClient.initialize(settings)) {
// Create a new Album with at title
Album createdAlbum = photosLibraryClient.createAlbum("My Album");
// Get some properties from the album, such as its ID and product URL
String id = album.getId();
String url = album.getProductUrl();
} catch (ApiException e) {
// Error during album creation
}
But I don't understand how to create Credentials object to pass it to the FixedCredentialsProvider.create() method
Could you please provide me with some explanation/links about it?
You can create a UserCredentials Object and pass it
UserCredentials.newBuilder()
.setClientId("your client id")
.setClientSecret("your client secret")
.setAccessToken("Access Token")
.build()
Go through this answer
https://stackoverflow.com/a/54533855/6153171
Or check out this complete project on github
https://github.com/erickogi/AndroidGooglePhotosApi
The FixedCredentialsProvider.create(..) call takes in a com.google.auth.Credentials object. For the Google Photos Library API, this should be a UserCredentials object, that you can create UserCredentials.Builder that is part of the Google OAuth library. There you set the refresh token, client ID, client secret, etc. to initialise the credentials. Getting a refresh token requires your app to complete the
GoogleAuthorizationCodeFlow that prompts the user for authorization and approval.
You can check out the sample implementation on GitHub, but this is the relevant code:
GoogleAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow.Builder(
GoogleNetHttpTransport.newTrustedTransport(),
JSON_FACTORY,
clientSecrets,
selectedScopes)
.setDataStoreFactory(new FileDataStoreFactory(DATA_STORE_DIR))
.setAccessType("offline")
.build();
LocalServerReceiver receiver =
new LocalServerReceiver.Builder().setPort(LOCAL_RECEIVER_PORT).build();
Credential credential = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
return UserCredentials.newBuilder()
.setClientId(clientId)
.setClientSecret(clientSecret)
.setRefreshToken(credential.getRefreshToken())
.build();
There are a few moving parts involved, but the Google Photos Library API client library works with the Google Authentication library to handle OAuth authentication.
You need to understand about OAuth 2 first:
https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2
Then you can look this answer https://stackoverflow.com/a/54533855/6153171
P/s:
1. Grant Type: Authorization Code
Google developer console : credential is web client.
GoogleApiClient -> addScope, requestServerCode -> grand permission -> get account -> getServerAuthenCode -> get AccessToken (https://stackoverflow.com/a/54533855/6153171)
-> I tested and it works well. You can follow this way
Grant Type: Implicit
Google developer console : credential is android or ios app.
GoogleApiClient -> addScope, requestTokenID -> grand permission -> get account -> getTokenID -> get AccessToken. I didn't try successfully to grant authorization for google photo api. But with firebase authentication, we can use this way because firebase support class util for us.

Access Google Sheets API from Java servlet

I am trying to write a Google App Engine app, which accesses a spreadsheet from Google Drive by using the Google Sheets API. I have found an example from Google, which shows how to access the Calendar from Google app engine application: https://github.com/google/google-api-java-client-samples/tree/master/calendar-appengine-sample
I took that as a base and try to replace the Calendar call with the SpreadSheet call. In this example, the Calendar data is accessed by this code:
static Calendar loadCalendarClient() throws IOException {
String userId = UserServiceFactory.getUserService().getCurrentUser().getUserId();
Credential credential = newFlow().loadCredential(userId);
return new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).build();
}
However, Sheets API does not provide any Sheets.Builder. Instead, from another example (https://developers.google.com/google-apps/spreadsheets/), I found that they use the following code:
SpreadsheetService service = new SpreadsheetService("MySpreadsheetIntegration-v1");
// TODO: Authorize the service object for a specific user (see other sections)
So, the trick is to authorize the Sheets service with the credentials. I'm trying to merge these examples, but without success:
String userId = UserServiceFactory.getUserService().getCurrentUser().getUserId();
Credential credential = flow.loadCredential(userId); // the flow object which was used to create an OAuth flow
SpreadsheetService service = new SpreadsheetService("AppName");
credential.refreshToken();
service.setOAuth2Credentials(credential);
URL SPREADSHEET_FEED_URL = new URL("https://spreadsheets.google.com/feeds/spreadsheets/private/full");
SpreadsheetFeed feed = service.getFeed(SPREADSHEET_FEED_URL, SpreadsheetFeed.class);
After calling the service.getFeed method I receive an exception:
com.google.gdata.client.GoogleService$SessionExpiredException: OK
Token invalid - AuthSub token has wrong scope</TITLE>
Token invalid - AuthSub token has wrong scope</H1>
Error 401
at com.google.gdata.client.http.GoogleGDataRequest.handleErrorResponse(GoogleGDataRequest.java:570)
at com.google.gdata.client.http.HttpGDataRequest.checkResponse(HttpGDataRequest.java:560)
at com.google.gdata.client.http.HttpGDataRequest.execute(HttpGDataRequest.java:538)
at com.google.gdata.client.http.GoogleGDataRequest.execute(GoogleGDataRequest.java:536)
at com.google.gdata.client.Service.getFeed(Service.java:1135)
Any ideas how to fix that?

Upload videos to Youtube from my web server in Java

My goal is to upload videos that are uploaded to my web server to Youtube on my own channel, not the users' Youtube account (my web server is acting as a proxy).
I found the sample code for uploading video to Youtube here with the credential acquired this way. The problem that I have with this sample is that it writes to disk the credential, and it opens an http server. Since my web server can potentially have a lot of users uploading their videos concurrently, the credential file location has to be dynamic, and multiple binding to the same http port is not possible. Further more, after searching through other writing about uploading to Youtube, I think this approach is for users uploading to their Youtube account.
Could you share your experiences/code sample/solutions for my scenario? In short I am just trying to automate the process of me opening up Youtube dashboard, and uploading videos to a channel in my Youtube.
In general, starting at API V3, Google prefers OAuth2 over other mechanism, and uploading a video (or any other action that modifies user data) requires OAuth2.
Fortunately, there is a special kind of token called refresh token to the rescue. Refresh token does not expire like normal access token, and is used to generate normal access token when needed. So, I divided my application into 2 parts:
The 1st part is for generating refresh token, which is a Java desktop app, meant to be run by a user on a computer. See here for sample code from Google.
The 2nd part is is part of my web application, which uses a given refresh token to create a credential object.
Here is my implementation in Scala, which you can adapt to Java version easily:
For generating a refresh token, you should set the accessType to offline for the authorization flow. Note: if a token already exists on your system, it won't try to get new token, even if it does not have refresh token, so you also have to set approval prompt to force:
def authorize(dataStoreName: String, clientId: String, clientSecret: String): Credential = {
val builder = new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT,
JSON_FACTORY,
clientId,
clientSecret,
Seq(YouTubeScopes.YOUTUBE_UPLOAD)
)
val CREDENTIAL_DIRECTORY = s"${System.getProperty("user.home")}/.oauth-credentials"
val fileDataStoreFactory = new FileDataStoreFactory(new java.io.File(CREDENTIAL_DIRECTORY))
val dataStore: DataStore[StoredCredential] = fileDataStoreFactory.getDataStore(dataStoreName)
builder.setCredentialDataStore(dataStore).setAccessType("offline").setApprovalPrompt("force")
val flow = builder.build()
val localReceiver = new LocalServerReceiver.Builder().setPort(8000).build()
new AuthorizationCodeInstalledApp(flow, localReceiver).authorize("user")
}
val credential = authorize(dataStore, clientId, clientSecret)
val refreshToken = credential.getRefreshToken
For using the refresh token on the server, you can build a credential from a refresh token:
def getCredential = new GoogleCredential.Builder()
.setJsonFactory(JSON_FACTORY)
.setTransport(HTTP_TRANSPORT)
.setClientSecrets(clientId, clientSecret)
.build()
.setRefreshToken(refreshToken)
I have have bypassed the whole AuthorizationCodeInstalledApp authorize() method and created a new subclass which bypasses the jetty server implementation process.
The methods are as follows
getAuthorizationFromStorage : Get access token from stored credentials.
getAuthorizationFromGoogle : Get the authentication with the credentials from Google creates the url that will lead the user to the authentication page and creating a custom defined name-value pair in the state parameter. The value should be encoded with base64 encoder so we can receive the same code redirected from google after authentication.
saveAuthorizationFromGoogle : Save the credentials that we get from google.
Create the GoogleAuthorizationCodeFlow object from the credentialDatastorfrom the response received from the google after authentication.
Hit google to get the permanent refresh-token that can be used to get the accesstoken of the user any time .
Store the tokens like accesstoken and refreshtoken in the filename as userid
Checkout the code Implementation here

How to get google access token from refresh token using google java api?

How to get new google's access token using refresh token programatically using the google java token.
I have found out the following code, and it's the working solution for getting the new access token, and there might be some other alternative for same :-TokenResponse response = new GoogleRefreshTokenRequest(httpTransport, jsonFactory, token, clientId, clientSecret).execute(); in the code response could be used to generate various google services again and here token is the response token.

NoLinkedYoutubeAccount error 401 when uploading videos on Youtube with java

i would like to upload videos on youtube from my java web application:
I want to receive (server side) my authToken and form-action so to upload a video.
I've created a new google/youtube account
I've created a youtube channel in my account
i've created a new project in my google console api as a Service Account
Now i'm trying to implement my code with oAuth 2.0.
I've got the accessToken but, when i try to call the service getFormUploadToken(url, object) the response is always the same "NoLinkedYoutubeAccount error 401".
i've also verified the account by the google support page http://www.youtube.com/my_account_unlink but it's seems ok.
Does anybody have an idea about this problem?
This is my code:
HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
JsonFactory JSON_FACTORY = new JacksonFactory();
String accessToken = "";
GoogleCredential credential = null;
credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(CLIENT_EMAIL)
.setServiceAccountScopes("http://gdata.youtube.com")
.setServiceAccountPrivateKeyFromP12File(new File(PRIVATE_KEY_PATH))
.build();
credential.refreshToken();
accessToken = credential.getAccessToken();
YouTubeService service = new YouTubeService(CLIENT_ID, DEV_KEY);
service.setAuthSubToken(accessToken, null);
VideoEntry newEntry = new YouTubeMediaGroup mg = newEntry.getOrCreateMediaGroup();
mg.setTitle(new MediaTitle());
mg.getTitle().setPlainTextContent("My Test Movie");
URL uploadUrl = new URL("http://gdata.youtube.com/action/GetUploadToken");
FormUploadToken token = service.getFormUploadToken(uploadUrl, newEntry);
Thanks a lot,
Albert III
As the error say, you have not linked the account credential to youtube.
You can solve that problem:
- Connecting with the account used on the app in www.youtube.com
- Trying to upload a video
- Setting name and surname when youtube ask, and process to link to gmail.
Done!!! I tried before using my app to upload the video using Firefox.
You can't associate a YouTube channel with a Service Account, and you're trying to upload under the context of the Service Account.
Instead of using Service Accounts, you should go through the OAuth 2 flow and authorize access while logged in to the browser using the account that you actually want to upload into.
I understand the benefits of using Service Accounts, but YouTube is not set up to work with them at this time.
If you have created youtube account and if has been linked to your google account, then make sure you create your own channel in your youtube.
This will allow the API to upload videos to your created channel.
Hope it helps.

Categories