I'm trying to connect my app to google drive using the driveAPI but I got an IOException when I tried to get the input stream of the credential path.
public Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT)
throws IOException {
// Load client secrets.
InputStream in = new FileInputStream(CREDENTIALS_FILE_PATH);//getApplicationContext().getAssets().open(CREDENTIALS_FILE_PATH);//MainActivity.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(8888).build();
Credential credential = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
//returns an authorized Credential object.
return credential;
}
And this is the path:
private static final String CREDENTIALS_FILE_PATH = "CapturaVideo/app/src/main/assets/credentials.json"; // "credentials.json";`
Here is my project's file structure:
enter image description here
I was trying with diferent lines of instructions but I get the same error
//getApplicationContext().getAssets().open(CREDENTIALS_FILE_PATH);
//MainActivity.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
First
First of all, you have to check your assets folder. If it exists in your project navigate to Proj-Name\app\src\main and see if there have assets folder. And if it is available? check your credentials.json file is it exists? inside the folder. If not you have to create a assets folder.
Second about your code snippet
According to your code snippet, You don't need to define their path! Only you need just specify their name credentials.json.
getApplicationContext().getAssets().open("credentials.json")
TL;DR
Sometimes. If you are using a room database and if you set room.schemaLocation to export their schemas. The project will automatically create an assets folder but it is not assets. Also, it will display on the Project sidebar. That is schemas folder. You can check it like this. Right-click that assets folder and navigate to open-in option go to explorer. (If it goes to schemas that's what I said.)
-Hope you understand.
-Thank you!
Related
I am trying to use google sheets apis in my java web application. I am hosting my application in "http://localhost:8080" port, and I generated credentials.json file from google cloud console and added "http://localhost:8080/home" as redirect uri while generating the file.
this is my code to generate Credential object
private Credential authorize() throws Exception{
File file = new ClassPathResource(CREDENTIALS_FILE_PATH).getFile();
InputStream in = new FileInputStream(file);
GoogleClientSecrets googleClientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
List<String> scopes = Collections.singletonList(SheetsScopes.SPREADSHEETS);
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow
.Builder(
GoogleNetHttpTransport.newTrustedTransport(),
JSON_FACTORY,
googleClientSecrets,
scopes)
.setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
.setAccessType("offline")
.build();
LocalServerReceiver localServerReceiver = new LocalServerReceiver
.Builder().setPort(8080).setCallbackPath("/home").build();
Credential credential = new AuthorizationCodeInstalledApp(flow,localServerReceiver).authorize("user");
return credential;
}
As my application is being hosted on port:8080, i used 8080 as port in redirect uri, but when i run the project, it is throwing BindException:address already in use as port 8080 is where i host my application. when i use any other port in setPort(), 404 error is occuring. I am stuck with this for more than a day and i dont understand why i cant use 8080 port because thats where i am hosting my application.
this is the error i am getting when i tried to access google sheets from port 8888
HTTP ERROR: 404
Problem accessing /home. Reason:
NOT_FOUND
Powered by Jetty://
Scenario: I am working on a Web Application on Google AppEngine where users have to access files from their own Google Drive. I have looked for online help and this is what I have figured out.
I have used this link for help that worked fine while testing with local machine
https://github.com/gsuitedevs/java-samples/blob/master/drive/quickstart/src/main/java/DriveQuickstart.java
Step 1 (Seemed simple): Enable Google Drive API and Setup necessary credential, i.e. OAuth 2.0 Client ID for Web Application. (This is done while enabling IAP on Google AppEngine, so I did not do it again. Whenever anyone opens the web application, he/she is asked to authenticate via iap.googleapis.com and details saved. This works fine). Also, I have added Google Drive Scopes to the OAuth consent screen (../auth/drive.appdata & ../auth/drive.file) that don't need verification by Google.
Step 2: Downloaded the credentials.json from OAuth Client ID and stored inside "resources" folder created in the root of application package (inside main folder, next to java and webapp folders)
Step 3: I have created a testing class (GoogleDriveServiceTest.class) that includes following code:
String USER_ID1 = UserServiceFactory.getUserService().getCurrentUser().getUserId();
List<String> SCOPES = Collections.singletonList(DriveScopes.DRIVE_METADATA_READONLY);
NetHttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
InputStream inputStream =
GoogleDriveServiceTest.class.getResourceAsStream("/credentials.json");
if (inputStream == null)
throw new FileNotFoundException("Required credentials file not found");
GoogleClientSecrets googleClientSecrets =
GoogleClientSecrets.load(jsonFactory, new InputStreamReader(inputStream));
AppEngineDataStoreFactory appEngineDataStoreFactory =
AppEngineDataStoreFactory.getDefaultInstance();
//IS SOMETHING MISSING HERE???
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow
.Builder(httpTransport, jsonFactory, googleClientSecrets, SCOPES)
.setDataStoreFactory(appEngineDataStoreFactory)
.setAccessType("offline")
.build();
Now I am trying to create the credential to be used for accessing Google Drive with this line:
Credential credential = flow.loadCredential(USER_ID1);
that is returning null.
In my opinion I am missing to assign the credentials to AppEngineDataStoreFactory based on what I have seen in the example from the github link above. However, I am not sure if this is the issue, and if it is, how do I resolve it.
Is there a straight forward way to assign credentials using logged in userID obtained from
UserServiceFactory.getUserService().getCurrentUser().getUserId() ? Or should I be obtaining accetoken and create the credential? if so, how?
(I don't want to use javascript as the same does not seem suitable for web application)
Any help would be great!!!!
PS: I also wanted to add a point that user needs to access only files added by the same web application either via web or from android
Update #1 responding to #Aerials:
Here is the code I was trying with to get the TokenResponse:
VerificationCodeReceiver receiver = new GooglePromptReceiver();
(I know above one is not the right option, but I am not able to find any other)
AuthorizationCodeRequestUrl authorizationUrl =
flow.newAuthorizationUrl().setRedirectUri(receiver.getRedirectUri());
String code = receiver.waitForCode();
(Above line returns: java.util.NoSuchElementException: No line found)
TokenResponse tokenResponse =
flow.newTokenRequest(code).setRedirectUri(redirectUri).execute();
Update #2 Code that worked in getting the TokenResponse and rest of the tasks of creating a Credential and connect to Google Drive successfully:
GenericUrl genericUrl = new GenericUrl(request.getRequestURL().toString());
genericUrl.setRawPath("/googleDriveTest");
String redirectUri = genericUrl.build();
(redirectUri should match with authorised redirect URI inside OAuth ClientID under GCP API Credentials. If you added it now, you need to redownload the credentials.json file)
String redirectUrl = authorizationCodeFlow
.newAuthorizationUrl()
.setRedirectUri(redirectUri)
.build();
String authorizationCode = request.getParameter("code");
if (authorizationCode == null || authorizationCode.isEmpty())
response.sendRedirect(redirectUrl);
TokenResponse tokenResponse = authorizationCodeFlow
.newTokenRequest(authorizationCode)
.setRedirectUri(redirectUri).execute();
authorizationCodeFlow.createAndStoreCredential(tokenResponse, USER_ID1);
Credential credential = authorizationCodeFlow.loadCredential(USER_ID1);
Drive service = new Drive.Builder(httpTransport, jsonFactory, credential)
.setApplicationName("myapplicationname")
.build();
You need to first create and store the credentials in the flow's credential store:
createAndStoreCredential(TokenResponse response, String userId)
to be able to load them with loadCredential(String userId)
The loadCredential() method will return credential found in the credential store of the given user ID or null for none found.
I work on student project where I have to use GMAIL API (Java), to connect to mail server, get new messages and download attachments if there is any. I already done this with JavaMail API, but mail server that should use app doesn't accept IMAP and POP3 protocols, it has own web service.
I have two problems.
I have troubles even with starting project in eclipse.
First, I have no idea how to set up connection with mail server (for example gmail account) and how to provide username and password. I saw that gmail api for authorization uses Oauth2.
Second one is maybe easier to solve. When I have established connection to mail server, how to fetch unseen mails and download attachments?
I guess that second part I could do on my own, but without
connection its even useless to try.
I was reading official documentation for few days and I am quite confused.
(Maybe if you have some code sample or similar example it would be nice)
EDIT 1:
Done that, now I have this error
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
.setAccessType("offline")
.build();
setAccessType is not found in com.google.api.client.auth.oauth2.AuthorizationCodeFlow.Builder
All Imports from Quickstart are there.
EDIT 2:
I am quite confused now
Exception in thread "main" java.io.FileNotFoundException: Resource not found: /resources/credentials.json
Line:
private static final String CREDENTIALS_FILE_PATH = "/resources/credentials.json";
File&Folder organization
When I check System.out.print(System.getProperty("user.dir"));
I get F:\NBS\eclipse\FetchMail
EDIT 3:
Deleted all files and started over again but eclipse still looks blind
File not found
EDIT 4:
Tested method .getResourceAsStream(path) inside Main method and it finds credential.json inside \eclipse\FetchMail or any other file i want
Then moved file to \eclipse\FetchMail\resources and call .getResourceAsStream("/resources/credentials.json") also finds file.
But when try this in getCredentials method from Quickstart, there is FileNotFound exception.
private static final String CREDENTIALS_FILE_PATH = "/resources/credentials.json";
private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
// Load client secrets.
InputStream in = Main.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(8888).build();
return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
}
Google uses Oauth2 to authorize and authenticate accounts in order to use the Google APIs. To do so, follow the next steps:
In your Google Developer Console, click on Credentials.
Click on CREATE CREDENTIALS and Select Oauth Client Id
In this case, choose Desktop App
Set any Name and click on Create
You will get a screen with the Client ID and the Client Secret. These keys will authorize your account to use the APIs. They are stored in the credentials file. You don't need to do anything with them, so close the window.
Download the credential's JSON file.
In the Quickstart code, you will notice this line:
private static final String CREDENTIALS_FILE_PATH = "/credentials.json";
You have to set the path of your credentials file. Change the name of the file to yours.
When running the code for the first time, you will get a link to accept the permissions specified in the Scopes. This will generate an Access token which allows the application to access the API without asking for human interaction until it expires.
Finally solved, changed .getResourceAsStream with FileInputStream(path) constructor and it works.
I am trying to use google drive.api I ran
private static Credential authorize() throws Exception {
// load client secrets
InputStream in = new FileInputStream("C:\\Users\\orion\\OneDrive\\Documents\\GitHub\\teachervoiceorganization\\JavaProject\\client_id.json");
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY,
new InputStreamReader(in));
if (clientSecrets.getDetails().getClientId().startsWith("515427348790")
|| clientSecrets.getDetails().getClientSecret().startsWith("i50nkSMoqVegC0UdkD1W8g3Y")) {
System.out.println(
"Enter Client ID and Secret from https://code.google.com/apis/console/?api=drive "
+ "into drive-cmdline-sample/src/main/resources/client_secrets.json");
}
// set up authorization code flow
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, JSON_FACTORY, clientSecrets,
Collections.singleton(DriveScopes.DRIVE_FILE)).setDataStoreFactory(dataStoreFactory)
.build();
// authorize
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
}
I get the issue with
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
Where is the user id located? I have looked on the https://console.developers.google.com and there is no luck. anything will help.
The Google user ID is encoded as the sub of the JWT returned from the call to exchange the Auth Code for tokens. You're using the Java client library which obfuscates everything, so where the JWT token is exposed is anybody's guess. My personal advice is discard the library and just call the two OAuth URLs directly.
The steps are:-
Construct the OAuth request URL containing your client ID, scopes and callback URL
Redirect to that URL
When the browser redirects back to your callback Servlet, call the token endpoint to request the tokens including the identity.
This is all described really well at https://developers.google.com/identity/protocols/OAuth2WebServer
Nb, you need to include the email scope as well as the appropriate Drive scope(s).
I am trying to upload videos to Youtube with authorization code.
public Credential authorize(List scopes, String credentialDatastore) throws IOException, URISyntaxException {
// Load client secrets.
URI filePath = new URI (GOOGLE_APIKEY);
Reader clientSecretReader =new InputStreamReader(new FileInputStream(filePath.toString()));
//Reader clientSecretReader = new InputStreamReader(Auth.class.getResourceAsStream(GOOGLE_APIKEY));
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, clientSecretReader);
// Checks that the defaults have been replaced (Default = "Enter X here").
if (clientSecrets.getDetails().getClientId().startsWith("Enter")
|| clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) {
System.out.println(
"Enter Client ID and Secret from https://console.developers.google.com/project/_/apiui/credential "
+ "into src/main/resources/client_secrets.json");
System.exit(1);
}
// This creates the credentials datastore at ~/.oauth-credentials/${credentialDatastore}
FileDataStoreFactory fileDataStoreFactory = new FileDataStoreFactory(new File(System.getProperty("user.home") + "/" + CREDENTIALS_DIRECTORY));
DataStore datastore = fileDataStoreFactory.getDataStore(credentialDatastore);
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, scopes).setCredentialDataStore(datastore).build();
// Build the local server and bind it to port 8080
LocalServerReceiver localReceiver = new LocalServerReceiver.Builder().setPort(8080).build();
// Authorize.
return new AuthorizationCodeInstalledApp(flow, localReceiver).authorize("user");
}
This is working and the user has to authenticate everytime when the video will be uploaded.
Now I want the to upload videos using the accesstoken generated from the refreshtoken which I already have .
But need to integrate in my Auth file which has the LocalServerReceiver as uses Jetty server internally.
I have written the code to get the accesstoken from refresh token .Please help me to integrate it .
public GoogleCredential getCredentials(String clientId,String clientSecret,JsonFactory jsonFactory,HttpTransport transport,String refreshToken) throws IOException{
GoogleCredential credential = new GoogleCredential.Builder()
.setClientSecrets(clientId, clientSecret)
.setTransport(transport)
.setJsonFactory(jsonFactory)
.build();
credential.setRefreshToken(refreshToken);
// Do a refresh so we can fail early rather than return an unusable credential
credential.refreshToken();
String authCode=credential.getAccessToken();
return credential;
}
There was specifically two problems that I was facing during Youtube video upload using google-java-api
An instance of jetty server instance which will be listening constantly until the response is coming from Google as mentioned in the redirect url.
Though there is a function called setHost() inside new LocalServerReceiver.Builder() class which responsible for creating a local jetty server instance, was throughing a Cannot assign requested address error everytime a host name was given irrespective of the port which did not matter.
The whole authorisation process is done in the AuthorizationCodeInstalledApp class's authorize method whose primary functions are as follows
Create an url that will ask the user to give access to the app .
After successful authentication a code will be received (An instance of jetty server continuously listens untill the code is received ).
Exchange the code just received with the accesstoken and refreshtoken for offline upload.
Store the credentials that we just received from google.
To decouple the whole process I have created a new class ExtendedAuthorizationCodeInstalledApp which extends the original AuthorizationCodeInstalledApp and created each method for each functions in the class.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
The code implementation is here
Thanks #KENdi for your suggestion...