Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to authenticate Google Drive without requiring the user to copy/paste auth code?

I'm playing around with the DriveCommandLine applicaiton to learn the Drive API a bit. I'm just wondering if it is possible to authenticate my desktop application with Google Drive without the user needing to copy/paste an auth code from the browser? But rather just have a token passed back to the app from the browser? I am able to do this with Dropbox API and with the Google Documents List API, but cannot figure out how to get this working with the Google Drive API.

Thanks.

Google Drive API - DriveCommandLine sample app (slightly modified):

public class DriveCommandLine {

  private static String CLIENT_ID = APPCONSTANTS.Google.CONSUMER_KEY;
  private static String CLIENT_SECRET = APPCONSTANTS.Google.CONSUMER_SECRET;

  private static String REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob";

  public static void main(String[] args) throws IOException, URISyntaxException {
    HttpTransport httpTransport = new NetHttpTransport();
    JsonFactory jsonFactory = new JacksonFactory();

    GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
        httpTransport, jsonFactory, CLIENT_ID, CLIENT_SECRET, Arrays.asList(DriveScopes.DRIVE))
        .setAccessType("offline")
        .setApprovalPrompt("force").build();

    String url = flow.newAuthorizationUrl().setRedirectUri(REDIRECT_URI).build();
    System.out.println("Enter authorization code:");
    Desktop.getDesktop().browse(new URI(url));
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String code = br.readLine();

    GoogleTokenResponse response = flow.newTokenRequest(code).setRedirectUri(REDIRECT_URI).execute();
    GoogleCredential credential = new GoogleCredential().setFromTokenResponse(response);

    //Create a new authorized API client
    Drive service = new Drive.Builder(httpTransport, jsonFactory, credential).build();
}

Google Documents List API:

    public void authenticate(){
            GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
            oauthParameters.setOAuthConsumerKey(APPCONSTANTS.Google.CONSUMER_KEY);

            OAuthSigner signer;
            if (APPCONSTANTS.Google.USE_RSA_SIGNING) {
                    signer = new OAuthRsaSha1Signer(APPCONSTANTS.Google.CONSUMER_SECRET);
            } else {
                oauthParameters.setOAuthConsumerSecret(APPCONSTANTS.Google.CONSUMER_SECRET);
                signer = new OAuthHmacSha1Signer();
            }

            GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(signer);

            oauthParameters.setScope(APPCONSTANTS.Google.SCOPES);

            oauthHelper.getUnauthorizedRequestToken(oauthParameters);

            String requestUrl = oauthHelper.createUserAuthorizationUrl(oauthParameters);

            Desktop desktop = Desktop.getDesktop();
            URI url = new URI(requestUrl);
            desktop.browse(url);

            String token = oauthHelper.getAccessToken(oauthParameters);
    }
like image 800
PseudoPsyche Avatar asked Sep 20 '12 21:09

PseudoPsyche


People also ask

How do you authenticate Google Drive?

In the search results, click Google Drive API, and then click Enable API. In the menu on the left, click Credentials. In the OAuth Consent Screen tab, enter a valid email address and application name, and click Save. In the Credentials tab, click Add credentials, and select OAuth client ID .

How does Google do authentication?

The Authenticator app is based on the time-based one-time password (TOTP) system specified in the IETF's RFC 6238 document. The TOTP algorithm generates a six-digit passcode that factors in the current time of day to ensure that each passcode is unique. Passcodes are changed every 30-60 seconds for further security.

Does Google support PKCE?

Google's documentation for "Mobile and Desktop apps" does direct developers to use a PKCE Authorization Code flow. Clients using Google Android, iOS or windows store credential types with PKCE may omit the client_secret (see the note on the refresh token parameter table - and confirmed by Cristiano).


2 Answers

The command line samples were written for simplicity, not necessarily the best user experience. In this case, they're running as local apps and are using the installed app flow for OAuth 2.0. That flow does have a mode where the redirect_uri can point to localhost, but it requires starting up a temporary web server to receive the redirect. Rather than complicate the sample, it uses the OOB mode which requires copy/pasting the code.

If you're building a desktop app, I'd encourage going the route of redirecting to localhost as it is a better UX.

See https://developers.google.com/accounts/docs/OAuth2InstalledApp for more info.

like image 162
Steve Bazyl Avatar answered Oct 11 '22 07:10

Steve Bazyl


Step 1: Generate the URL using offline access type

flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, jsonFactory, CLIENT_ID, CLIENT_SECRET, Arrays.asList(DriveScopes.DRIVE))
.setAccessType("offline")
.setApprovalPrompt("auto").build();
String url = flow.newAuthorizationUrl().setRedirectUri(REDIRECT_URI).build();

Step 2: Store the credentials accessToken and refreshToken

GoogleTokenResponse response = flow.newTokenRequest(code).setRedirectUri(REDIRECT_URI).execute();
            GoogleCredential credential = new GoogleCredential.Builder().setTransport(httpTransport)
                .setJsonFactory(jsonFactory)
                .setClientSecrets(CLIENT_ID, CLIENT_SECRET)
                .build()
                .setFromTokenResponse(response);
String accessToken = credential.getAccessToken();
String refreshToken = credential.getRefreshToken();

Step 3: Reuse tokens when needed

GoogleCredential credential1 = new GoogleCredential.Builder().setJsonFactory(jsonFactory)
.setTransport(httpTransport).setClientSecrets(CLIENT_ID, CLIENT_SECRET).build();
credential1.setAccessToken(accessToken);
credential1.setRefreshToken(refreshToken);
Drive service = new Drive.Builder(httpTransport, jsonFactory, credential1).build();

Step 4: Understand OAuth to handle errors and refreshing of the tokens

like image 44
Vinay Sheshadri Avatar answered Oct 11 '22 08:10

Vinay Sheshadri