Youtube live streaming API giving livePermissionBlocked error - youtube-data-api

I am trying to setup youtube live streaming APIs using service account delegation. I have done all the necessary steps for service account delegation on my domain.
I have a youtube channel owned by a user with email id of this domain name. Channel has more than 10k subscribers and has all the necessary permissions to live stream (I can live stream via youtube studio).
While using youtube java APIs, i am getting this error :
{
"code" : 403,
"errors" : [ {
"domain" : "youtube.liveBroadcast",
"message" : "The user is blocked from live streaming.",
"reason" : "livePermissionBlocked",
"extendedHelp" : "https://support.google.com/youtube/answer/2853834"
} ],
"message" : "The user is blocked from live streaming."
}
I am attaching my code for reference
private static final Collection<String> SCOPES =
Arrays.asList("https://www.googleapis.com/auth/youtube.force-ssl");
private static final String APPLICATION_NAME = "youtubeLive";
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
/**
* Create an authorized Credential object.
*
* #return an authorized Credential object.
* #throws IOException
*/
public static Credential authorize(final NetHttpTransport httpTransport) throws IOException, GeneralSecurityException {
// Load client secrets.
InputStream in = new FileInputStream(CLIENT_SECRETS);
// GoogleClientSecrets clientSecrets =
// GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
// // Build flow and trigger user authorization request.
// GoogleAuthorizationCodeFlow flow =
// new GoogleAuthorizationCodeFlow.Builder(httpTransport, JSON_FACTORY, clientSecrets, SCOPES)
// .build();
// Credential credential = new AuthorizationCodeInstalledApp(flow, null).authorize("user");
// GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream(CLIENT_SECRETS))
// .createScoped(SCOPES);
GoogleCredential credential = new GoogleCredential.Builder()
.setServiceAccountScopes(SCOPES)
.setServiceAccountPrivateKeyFromP12File(new File("/Users/ashishjindal/Downloads/youtubelive-291213-be89f6b31144.p12"))
.setServiceAccountId("a******#youtubelive****.iam.gserviceaccount.com")
.setServiceAccountUser("USER#MY_DOMAIN.COM")
.setJsonFactory(JSON_FACTORY)
.setTransport(httpTransport)
.build();
return credential;
}
/**
* Build and return an authorized API client service.
*
* #return an authorized API client service
* #throws GeneralSecurityException, IOException
*/
public static YouTube getService() throws GeneralSecurityException, IOException {
final NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
Credential credential = authorize(httpTransport);
return new YouTube.Builder(httpTransport, JSON_FACTORY, credential)
.setApplicationName(APPLICATION_NAME)
.build();
}
#Scheduled(fixedDelay = 1000l)
public void test() throws IOException, GeneralSecurityException {
YouTube youtubeService = getService();
LiveBroadcast liveBroadcast = new LiveBroadcast();
// Add the contentDetails object property to the LiveBroadcast object.
LiveBroadcastContentDetails contentDetails = new LiveBroadcastContentDetails();
contentDetails.setEnableClosedCaptions(true);
contentDetails.setEnableContentEncryption(true);
contentDetails.setEnableDvr(true);
contentDetails.setEnableEmbed(true);
contentDetails.setEnableAutoStart(true);
contentDetails.setRecordFromStart(true);
contentDetails.setStartWithSlate(true);
liveBroadcast.setContentDetails(contentDetails);
LiveBroadcastSnippet snippet = new LiveBroadcastSnippet();
snippet.setScheduledEndTime(new DateTime("2030-10-10T00:00:00"));
snippet.setScheduledStartTime(new DateTime("2029-10-10T00:00:00"));
snippet.setTitle("Test broadcast");
snippet.setChannelId("CHANNEL ID OWNED BY MY USER");
liveBroadcast.setSnippet(snippet);
LiveBroadcastStatus status = new LiveBroadcastStatus();
status.setPrivacyStatus("unlisted");
liveBroadcast.setStatus(status);
YouTube.LiveBroadcasts.Insert request = youtubeService.liveBroadcasts()
.insert("snippet,contentDetails,status", liveBroadcast);
liveBroadcast = request.execute();
System.out.println(response);
}
EDIT : I have identified the root cause. I was passing the channel Id which belonged to a brand account which is further owned by this user. A user can have multiple brand accounts on youtube. Now my new issue is how to impersonate brand account using service-account.
Some useful threads I found :
YouTube API and brand account
Using Youtube Data API to Edit with Brand Account Playlist

The YouTube APIs does not support service accounts (as other Google APIs do).
Here is quote from the official API doc Move from ClientLogin to OAuth 2.0, the section Service Accounts do not work with the YouTube API (the emphasis below is mine):
Service accounts do not work for YouTube Data API calls because service accounts require an associated YouTube channel, and you cannot associate new or existing channels with service accounts. If you use a service account to call the YouTube Data API, the API server returns an error with the error type set to unauthorized and the reason set to youtubeSignupRequired.
Moreover, here is a text extracted from another place of the official docs that states that fact once more (the emphasis below is also mine):
This error is commonly seen if you try to use the OAuth 2.0 Service Account flow. YouTube does not support Service Accounts, and if you attempt to authenticate using a Service Account, you will get this error.
The context from which I extracted the above official statement is not subsumed to that you've shown above. Nonetheless, the fact remains.
Yet another quote asserting the above mentioned fact, this time from the Live Streaming API docs themselves (the emphasis below is mine too):
The service account flow supports server-to-server interactions that do not access user information. However, the YouTube Live Streaming API does not support this flow. Since there is no way to link a Service Account to a YouTube account, attempts to authorize requests with this flow will generate a NoLinkedYouTubeAccount error.
Consequently, you have to acknowledge that you cannot initiate a live broadcast using YouTube's corresponding APIs by means of a service account.

Related

OAuth2.0 authorization spring boot web application flow

i am using java library client for web application authentication, i produce authorization url using client secret and client id,also i provided a redirect url within google api console,but i don't know if it is necessary for me to create this server to receive refresh token?
i mean in production i should provide a separate server to receive the refresh token?(redirect url comes to this server)
the main problem is user should paste the produced url on browser by himself but i want to open browser authmaticly , the second one is about reciving the refresh token i am not sure about creating another server to recieve refreshcode and i can't use service accounts i am going with web flow authentication.
UserAuthorizer userAuthorizer =
UserAuthorizer.newBuilder()
.setClientId(ClientId.of(clientId, clientSecret))
.setScopes(SCOPES)
.setCallbackUri(URI.create(OAUTH2_CALLBACK_URL_CONFIGURED_AT_GOOGLE_CONSOLE))
.build();
baseUri = URI.create("http://localhost:" + simpleCallbackServer.getLocalPort());
System.out.printf(
"Paste this url in your browser:%n%s%n",
userAuthorizer.getAuthorizationUrl(loginEmailAddressHint, state, baseUri));
and this is local server to receive refresh token:
private static class SimpleCallbackServer extends ServerSocket {
private AuthorizationResponse authorizationResponse;
SimpleCallbackServer() throws IOException {
// Passes a port # of zero so that a port will be automatically allocated.
super(0);
}
/**
* Blocks until a connection is made to this server. After this method completes, the
* authorizationResponse of this server will be set, provided the request line is in the
* expected format.
*/
#Override
public Socket accept() throws IOException {
Socket socket = super.accept();
}
}
for those who struggling to get authorized using google oauth2.0 with spring boot
you cant redirect user to authorization url(which google authorization server gives to using your client id and client secret) use a controller to redirect user:
#GetMapping(value = "/redirect-user")
public ResponseEntity<Object> redirectToExternalUrl() throws URISyntaxException {
String url=gs.createUserAuthorizationUrl();
URI authorizationUrl = new URI(url);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setLocation(authorizationUrl);
return new ResponseEntity<>(httpHeaders, HttpStatus.FOUND);
}
at service layer createUserAuthorizationUrl() method is like below:
public String createUserAuthorizationUrl() {
clientId = "client-id";
clientSecret = "client-secret-code";
userAuthorizer =
UserAuthorizer.newBuilder()
.setClientId(ClientId.of(clientId, clientSecret))
.setScopes(SCOPES)
.setCallbackUri(URI.create("/oauth2callback"))
.build();
baseUri = URI.create("your-app-redirect-url-configured-at-google-console" + "your-spring-boot-server-port"); //giving redirect url
String redirectURL = userAuthorizer.getAuthorizationUrl(loginEmailAddressHint, state, baseUri).toString();
return redirectURL;
}
and let's create a controller to support the get request comming from google authorization server with an code. we are going to use that code to get access token from google.i get state and code by #RequestParam
and i also want to redirect user to my application.
#GetMapping(value = "/oauth2callback")
public ResponseEntity<Object> proceedeTOServer(#RequestParam String state,
#RequestParam String code) throws URISyntaxException {
String url="my-application-url-to-redirect-user";
URI dashboardURL = new URI(url);
HttpHeaders httpHeaders=new HttpHeaders();
httpHeaders.setLocation(dashboardURL);
gs.getCode(state,code);
return new ResponseEntity<>(httpHeaders,HttpStatus.FOUND);
}
and in getCode(code) in service layer i am going to send to code and receive the refresh token or access token:
UserCredentials userCredentials =userAuthorizer.getCredentialsFromCode(code, "your-app-redirect-url-configured-at-google-console" + "your-spring-boot-server-port");

Redirect Google Oauth2.0 LOCALHOST:9696/Callback On live Tomcat Server

I'm working on implementing Google drive API v3 in java spring boot. The application works fine on my local machine. I deployed the application in TOMCAT which is running on our UAT server for testing. I am following the procedure to Authorize my Google Drive API i got the consent window. I selected all the permissions that i require to access API and clicked allow button but right after that it redirected me to https://localhost:9696/callback URL which gives me page not found. I am stuck till here. do i need to provide my domain instead of default localhost has callback URL?
```
private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
// Load client secrets.
InputStream in = GoogleDriveService.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
if (in == null) {
throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
}
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
// Build flow and trigger user authorization request.
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY,
clientSecrets, SCOPES)
.setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
.setAccessType("offline").build();
LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(9696).build();
return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
}
Implementation Ref. API Doc:-
https://developers.google.com/drive/api/v3/quickstart/java?hl=en&authuser=2

How to validate facebook authorization token and sign up user using Spring(java)

I am developing an app whose frontend is written using React.js and the backend REST API is written using the Spring framework. I wanted to add social logins to my website, so after days of googling and research, I understood that OAuth2 is the solution. I came to know that the frontend should handle getting the authorization token from the Resource Server(Facebook here) and my backend(java) should validate that token and connect with Facebook to get an access token. Then that access token should be stored in my database along with the user details(e.g email).
Here is my requirement, once the user clicks on the "Continue with Facebook" button, my app should create there account in my own database using details - email and Name(the signup feature). And later whenever they click on this button again, they will be logged in not sign up. The way other websites handle it.
As of now, I have the button working in my app, which brings me the authorization token from Facebook.
Can someone please guide me the path I should follow here.
Also, any special attention to some error handling I should follow.
Here's the general approach using Spring Boot as a REST API backed by Spring Data JPA and Spring Security that works for iOS and ember.js together. There's probably libraries and what not that you can use but I'm just going to outline the fundamental flow.
Your user object needs a one to one mapping to a facebook account. Best practice would involve encrypting the authToken before storing in the DB
#Entity
class FacebookAccount {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
Long id
String facebookUserId
String authToken
#OneToOne
#JoinColumn(name="user_id")
User user
}
#Entity
class User{
...
#OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
FacebookAccount facebookAccount
}
Use the facebook Javascript SDK to get a User Access Token and the User's Facebook User ID. You'll get a response back from facebook in your react app that looks like this in the successful case:
{
status: 'connected',
authResponse: {
accessToken: '...',
expiresIn:'...',
reauthorize_required_in:'...'
signedRequest:'...',
userID:'...'
}
}
Hit some login endpoint with the info received in step 2 like /login/facebook. I cannot predict how your app is structured. In my app, this code is handled by my Authentication Filter that implements GenericFilterBean. I pass a header X-Auth-Facebook with the token.
Verify the token. I'm doing this in a class that implements AuthenticationProvider within the Authentication authenticate(Authentication authentication) throws AuthenticationException method. This class will need your App's Access Token accessToken and the user's Token userAccessToken:
URIBuilder builder = URIBuilder.fromUri(String.format("%s/debug_token", "https://graph.facebook.com"))
builder.queryParam("access_token", accessToken)
builder.queryParam("input_token", userAccessToken)
URI uri = builder.build()
RestTemplate restTemplate = new RestTemplate()
JsonNode resp = null
try {
resp = restTemplate.getForObject(uri, JsonNode.class)
} catch (HttpClientErrorException e) {
throw new AuthenticationServiceException("Error requesting facebook debug_token", e)
}
Boolean isValid = resp.path("data").findValue("is_valid").asBoolean()
if (!isValid)
throw new BadCredentialsException("Token not valid")
String fbookUserId = resp.path("data").findValue("user_id").textValue()
if (!fbookUserId)
throw new AuthenticationServiceException("Unable to read user_id from facebook debug_token response")
// spring data repository that finds the FacebookAccount by facebook user id
FacebookAccount fbookAcct = facebookAccountRepository.findByFacebookUserId(fbookUserId)
if(!fbookAcct){
// create your user here
// save the facebook account as well
} else{
// update the existing users token
fbookAcct.authToken = userAccessToken
facebookAccountRepository.save(fbookAcct)
}
// finish the necessary steps in creating a valid Authentication
I, personally, then create a token that my client's use when accessing my API (rather than have them continue to pass the facebook token with all requests).
I also need more user provided information to create the user (a chosen username, agreeing to terms and conditions, etc). So my actual implementation throws an EntityNotFoundException instead of creating the user, which my clients then use to pop up a registration form that provides only the fields I cannot get from facebook. On submit of this from the client, I hit my /signup/facebook endpoint with the facebook token and what's needed to create my user. I fetch the profile from facebook and create the user (automatically logging them in the process).
Edit: If you want to use Spring 0Auth, you could follow the example for creating a Spring 2 Oauth Rest Template
#Bean
public OAuth2ProtectedResourceDetails facebook() {
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
details.setId("facebook");
details.setClientId("233668646673605");
details.setClientSecret("33b17e044ee6a4fa383f46ec6e28ea1d");
details.setAccessTokenUri("https://graph.facebook.com/oauth/access_token");
details.setUserAuthorizationUri("https://www.facebook.com/dialog/oauth");
details.setTokenName("oauth_token");
details.setAuthenticationScheme(AuthenticationScheme.query);
details.setClientAuthenticationScheme(AuthenticationScheme.form);
return details;
}
#Bean
public OAuth2RestTemplate facebookRestTemplate(OAuth2ClientContext clientContext) {
OAuth2RestTemplate template = new OAuth2RestTemplate(facebook(), clientContext);
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON,
MediaType.valueOf("text/javascript")));
template.setMessageConverters(Arrays.<HttpMessageConverter<?>> asList(converter));
return template;
}
and then in use:
public String photos(Model model) throws Exception {
ObjectNode result = facebookRestTemplate
.getForObject("https://graph.facebook.com/me/friends", ObjectNode.class);
ArrayNode data = (ArrayNode) result.get("data");
ArrayList<String> friends = new ArrayList<String>();
for (JsonNode dataNode : data) {
friends.add(dataNode.get("name").asText());
}
model.addAttribute("friends", friends);
return "facebook";
}
I took the above request for friends from the project. it shouldn't be hard to tailor the above code I showed with debug_token to use the Spring OAuth rest template. Hope this helps :)

Server side authorization with Google Play Developer API?

Authorization is required to fetch information from the Google Play Developer API.
I know how to do this with Postman, but implementing authorization is much more cumbersome (redirect url, handling redirects, and so on...)
These would be the steps when you already have setup the auth data inside the Google Developer API Console.
1.) GET https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri=http://www.myurl.com/oauth2callback&client_id=1234567890.apps.googleusercontent.com
2.) get code which was sent to redirect url.
3.) POST https://accounts.google.com/o/oauth2/token
with
grant_type:authorization_code
code:[the code I got before]
client_id:1234567890.apps.googleusercontent.com
client_secret:[my client secret]
4.) Invoke GET https://www.googleapis.com/androidpublisher/v2/applications/packageName/purchases/subscriptions/subscriptionId/tokens/token
with:
Scope: https://www.googleapis.com/auth/androidpublisher
and:
access_token as query parameter I got before.
Now I want to do all this programmatically. Obviously not so easy. I thought the Google API Client Libraries will help, but I don't see, how these lib can help me with my use case.
For example classes like GoogleAuthorizationCodeFlow expect a user id at the moment of the request, but I not necessarily have one at this moment, so I wonder how this API should be used in a clean way.
Is there a clean way to handle OAuth2.0 easier / programmatically with some API to access Google Play Developer API? Otherwise I must implement it manually.
After lots of headache (like always with Google APIs and services) I figured out how one can access Google Play Developer API information (like billing) by using existing APIs.
1.) Create in Developer API Console a service account (JSON) key:
2.) Download this service-account-private-key.json file (don't mistake it with the OAuth2.0 client secret file!).
3.) In Google Play Developer Console go to Settings -> Users & Permissions -> Invite New User and set as user e-mail of the new user the client_email from the downloaded file. Assign the access rights you want to give to this users via the checkboxes inside this view (for example 'View financial data').
4.) Add the proper dependency to your project (version ...-1.23.0 does not work for me):
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-androidpublisher</artifactId>
<version>v2-rev50-1.22.0</version>
</dependency>
5.) Load the service-account-private-key.json file into your application. In my case it's a webserver:
#Singleton
#Startup
public class WebserverConfiguration
{
private String serviceAccountPrivateKeyFilePath;
/** Global instance of the HTTP transport. */
public static HttpTransport HTTP_TRANSPORT;
/** Global instance of the JSON factory. */
public static JsonFactory JSON_FACTORY;
private GoogleCredential credential;
#PostConstruct
public void init()
{
assignServiceAccountFileProperty();
initGoogleCredentials();
}
public String getServiceAccountPrivateKeyFilePath()
{
return serviceAccountPrivateKeyFilePath;
}
public GoogleCredential getCredential()
{
return credential;
}
private void initGoogleCredentials()
{
try
{
newTrustedTransport();
newJsonFactory();
String serviceAccountContent = new String(Files.readAllBytes(Paths.get(getServiceAccountPrivateKeyFilePath())));
InputStream inputStream = new ByteArrayInputStream(serviceAccountContent.getBytes());
credential = GoogleCredential.fromStream(inputStream).createScoped(Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER));
}
catch (IOException | GeneralSecurityException e)
{
throw new InitializationException(e);
}
}
private void newJsonFactory()
{
JSON_FACTORY = JacksonFactory.getDefaultInstance();
}
private void assignServiceAccountFileProperty()
{
serviceAccountPrivateKeyFilePath = System.getProperty("service.account.file.path");
if (serviceAccountPrivateKeyFilePath == null)
{
throw new IllegalArgumentException("service.account.file.path UNKNOWN - configure it as VM startup parameter in Wildfly");
}
}
private static void newTrustedTransport() throws GeneralSecurityException, IOException
{
if (HTTP_TRANSPORT == null)
{
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
}
}
}
6.) Now I am able the fetch Google Play Developer API information, e.g. reviews:
private void invokeGoogleApi() throws IOException
{
AndroidPublisher publisher = new AndroidPublisher.Builder(WebserverConfiguration.HTTP_TRANSPORT, WebserverConfiguration.JSON_FACTORY, configuration.getCredential()).setApplicationName("The name of my app on Google Play").build();
AndroidPublisher.Reviews reviews = publisher.reviews();
ReviewsListResponse reviewsListResponse = reviews.list("the.packagename.of.my.app").execute();
logger.info("review list response = " + reviewsListResponse.toPrettyString());
}
This worked.
I cannot test it yet, but I'm sure that fetching the billing information works as well:
private SubscriptionPurchase getPurchase() throws IOException
{
AndroidPublisher publisher = new AndroidPublisher.Builder(WebserverConfiguration.HTTP_TRANSPORT, WebserverConfiguration.JSON_FACTORY, configuration.getCredential()).setApplicationName("The name of my app on Google Play").build();
AndroidPublisher.Purchases purchases = publisher.purchases();
SubscriptionPurchase purchase = purchases.subscriptions().get("the.packagename.of.my.app", "subscriptionId", "billing token sent by the app").execute();
//do something or return
return purchase;
}
There are complete code samples and documentation for doing this in Java here
In the Java source code this authorizes like this
private static Credential authorizeWithServiceAccount(String serviceAccountEmail)
throws GeneralSecurityException, IOException {
log.info(String.format("Authorizing using Service Account: %s", serviceAccountEmail));
// Build service account credential.
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(serviceAccountEmail)
.setServiceAccountScopes(
Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER))
.setServiceAccountPrivateKeyFromP12File(new File(SRC_RESOURCES_KEY_P12))
.build();
return credential;
}

google drive Oauth 2.0 for java web application

My project is a java spark project that I have hosted on heroku. A part of the project requires that I download a particular file from my google drive into the application. I managed to set up everything when my application was running locally but as soon as I deployed the app it stopped working. This was regardless of the fact that when the app was running locally I used an Oauth2 client ID of type other and when I deployed the application I created a new one of type web application.
Below is a snippet of the authentication and download code:
public class AutoCalls {
/** Application name. */
private static final String APPLICATION_NAME = "calls-made";
private static final java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("target/classes/auth"), ".credentials/calls-made");
private static FileDataStoreFactory DATA_STORE_FACTORY;
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private static HttpTransport HTTP_TRANSPORT;
private static final List<String> SCOPES = Arrays.asList(DriveScopes.DRIVE);
static {
try {
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR);
} catch (GeneralSecurityException | IOException t) {
System.exit(1);
}
}
public static void startDownload() throws IOException, ParseException {
Drive serv = getDriveService();
// drive stuff deleted
}
public static Credential authorize() throws IOException {
InputStream in = new FileInputStream("target/classes/auth/client_secret_*****************************************.apps.googleusercontent.com.json");
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(DATA_STORE_FACTORY)
.setAccessType("offline")
.build();
Credential credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
System.out.println("Credentials saved to " + DATA_STORE_DIR.getAbsolutePath());
return credential;
}
public static Drive getDriveService() throws IOException {
Credential credential = authorize();
return new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName(APPLICATION_NAME)
.build();
}
}
Currently when I try to initiate the download I get a URL in the Heroku logs a follows:
2017-02-20T10:32:28.656820+00:00 app[web.1]: Please open the following address in your browser:
2017-02-20T10:32:28.656908+00:00 app[web.1]: https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=************-vvdi7u6bmp1vc90sdidtnuiftdi1t49c.apps.googleusercontent.com&redirect_uri=http://localhost:48085/Callback&response_type=code&scope=https://www.googleapis.com/auth/drive
When I try open the URL in a browser I get an error:
Error: redirect_uri_mismatch
I cannot find any good step by step tutorial on accessing google drive contents on a java web application so any help would be arreiciated.
Generally, if OAuth works on server-A but not on server-B, it's because the redirect URL hasn't been configured correctly on the API Console. There is no reason why you would need to use a different client-ID because a single client-ID can be configured with multiple URLs, eg your local host and your heroku server. Another possibility is the use of https.
There is a separate problem in your code where you iterate on lista.isEmpty(). You should be iterating on nextPageToken != null. See the answer to Google drive rest API, Download files from root folder only

Resources