I am working on a Spring-MVC application running on tomcat, in which I would like to use the functionality of a Google drive. I tried with a service account on my local machine and I had no problems. But when I downloaded the code on the server, the browser URL will not be open. Then I thought that I should not use a service account, I should use a regular web application account. Now when I do this, I get redirect_uri_mismatch.
I donβt understand anything, I set the redirect URL to the stream in JSON, why does it get redirect_url with random port numbers. If I change the port number in the browser url, it works fine. But still, on the server it will not open the browser URL, I see it in tomcat logs, but hell the URL does not open.
Here is my redirect URL from a Google app:
http://localhost/authorizeuser http://localhost:8080/ http://localhost:8080 http://localhost http://localhost:8080/Callback https://testserver.net/Callback http://testserver.net/Callback http://127.0.0.1
Here is my client_secret.json:
{"web": { "client_id": "clientid", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://accounts.google.com/o/oauth2/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_email": "clientemailstuff", "client_x509_cert_url": "certurlstuff", "client_secret": "itsasecret", "redirect_uris": ["http://localhost:8080/","http://localhost:8080"], "javascript_origins": ["https://testserver.net", "http://testserver.net","http://localhost:8080"] }}
And here is the code where I am trying to authenticate:
@Override public Credential authorize() throws IOException { InputStream in = DriveQuickstartImpl.class.getResourceAsStream("/client_secret.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(); flow.newAuthorizationUrl().setState("xyz").setRedirectUri("http://localhost:8080/Callback"); Credential credential = new AuthorizationCodeInstalledApp( flow, new LocalServerReceiver()).authorize("user"); if(credential!=null && credential.getRefreshToken() != null){ storeCredentials(credential); } return credential; }
This annoys me a lot because I set the redirect URL and it is simply ignored, and why the browser tab doesn't actually open when the application is deployed to the server.
Update Spring problem has also been fixed, the code below can be used to authorize GoogleDrive on a server with tomcat or others.
@Service @Transactional public class GoogleAuthorization{ @Autowired private DriveQuickstart driveQuickstart; private static final String APPLICATION_NAME ="APPNAME"; private static final java.io.File DATA_STORE_DIR = new java.io.File( "/home/deploy/store"); 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); private static final String clientid = "clientid"; private static final String clientsecret = "clientsecret"; private static final String CALLBACK_URI = "http://localhost:8080/getgooglelogin"; private String stateToken; private final GoogleAuthorizationCodeFlow flow; public GoogleAuthorization(){ try { HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport(); DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR); } catch (GeneralSecurityException | IOException e) { e.printStackTrace(); } flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, clientid, clientsecret, SCOPES).setAccessType("offline").setApprovalPrompt("force").build(); generateStateToken(); } public String buildLoginUrl() { final GoogleAuthorizationCodeRequestUrl url = flow.newAuthorizationUrl(); return url.setRedirectUri(CALLBACK_URI).setState(stateToken).build(); } private void generateStateToken(){ SecureRandom sr1 = new SecureRandom(); stateToken = "google;"+sr1.nextInt(); } public String getStateToken(){ return stateToken; } public void saveCredentials(final String authCode) throws IOException { GoogleTokenResponse response = flow.newTokenRequest(authCode).setRedirectUri(CALLBACK_URI).execute(); Credential credential = flow.createAndStoreCredential(response, null); System.out.println(" Credential access token is "+credential.getAccessToken()); System.out.println("Credential refresh token is "+credential.getRefreshToken());
Controller Method:
@RequestMapping(value = "/getgooglelogin") public String getGoogleLogin(HttpServletRequest request, HttpServletResponse response, HttpSession session,Model model) { // Below guy should be autowired if you want to use Spring. GoogleAuthorization helper = new GoogleAuthorization(); if (request.getParameter("code") == null || request.getParameter("state") == null) { model.addAttribute("URL", helper.buildLoginUrl()); session.setAttribute("state", helper.getStateToken()); } else if (request.getParameter("code") != null && request.getParameter("state") != null && request.getParameter("state").equals(session.getAttribute("state"))) { session.removeAttribute("state"); try { helper.saveCredentials(request.getParameter("code")); return "redirect:/dashboard"; } catch (IOException e) { e.printStackTrace(); } } return "newjsp"; }
newjsp just has a button for clicking on the url.