Blog

Implementing sign-in with Google’s OAuth 2 services

By  
Matti Tahvonen
Matti Tahvonen
·
On Jul 28, 2015 5:00:00 AM
·

Traditionally all public web apps have had their own authentication mechanisms, typically implemented with application specific username-password pairs. The approach is straightforward to set up for web developers, but also infamously difficult to do right (not at all or too weak hashing of passwords). The largest security issue with password-based authentication is not the implementation in the application, but the end user, who tends to use bad passwords and share them with various web apps.

 

OpenID was supposed to be the salvation for the password issue with web applications, but finally, OAuth and OAuth 2 standards have become the standard way to delegate authentication to separate services. These kinds of solutions are good for both the application developer (security wise) and especially for the end users who don’t need to remember lots of different passwords. Now that Google just closed its OpenID service in favor of OAuth 2 standard, it is probably a good time to publish a short tutorial of how to implement Google Sign-In in a server-side Java application. I implemented “Google Sign-In” to my recent example app for creating invoices, so let’s have a look at how to do that.

Explore more
Download our free guide to the Future of Web Apps

Scribe - the de-facto Java library for OAuth 2

The OAuth 2 specification is not simple. Do yourself a favor and don’t try to use it at the HTTP level. Google also suggests using for example their own OAuth library to simplify the usage. Scribe is another excellent Java library to help with generic OAuth 2 usage. From the Vaadin directory, you can actually even find an add-on built around Scribe, but it doesn’t support Google as a provider by default and the Scribe library can pretty easily be used alone with Vaadin as well.

In the invoice example application, there are no features at all we want to expose to non-authenticated users. We actually don’t limit the access to the application, but we just want to show user specific data. So we need an identifier for each user, email address, that Google will verify for us. Using email as a key gives us the freedom to change to some other authentication mechanism in the future. Google has lots of different services and APIs that one could use, but for our case, we only need the basic account information, including the email address.

To begin the usage, you need to sign into Google Developer console and register your web app for that service. You’ll also need to register allowed callback URLs for your application. I suggest registering “localhost versions” of your return URLs to make development and debugging easier. See Google’s OAuth 2 docs for more details.

Display the login screen

For users entering the application, we naturally want to display a login screen. In case the session scoped UserSession bean says the user has not yet logged in, we simply hide the main content of the application in UI init method and show a modal LoginWindow instance for the end user:

@Inject
Instance<LoginWindow> loginWindow;

@Override
protected void init(VaadinRequest request) {
    super.init(request);
    if (!userSession.isLoggedIn()) {
        getContent().setVisible(false);
        addWindow(loginWindow.get());
    }
}

Alternatively, we could swap the main content into a view with the login functionality.

OAuthService - the gateway to user-specific data

In LoginWindow we need to create a Scribe object called OAuthService. That needs to be configured for your provider. Google2Api is a reusable helper class that defines some details about Google’s OAuth 2 service. For most service providers Scribe contains these implementations, but for newer Google OAuth 2 I relied on an implementation available from Github. In addition to that, you need to provide the Google API key and the secret key that you got from the developer console. If you wish to use some other (OAuth 2 protected) services by Google, you should switch “email” scope to something else.

The callback URL is where the user is redirected after access has been granted, with the verifier key as a parameter. We’ll use the current location of the user’s browser (~ your effective application URL), but strip away a possible hash part.

private OAuthService createService() {
    ServiceBuilder sb = new ServiceBuilder();
    sb.provider(Google2Api.class);
    sb.apiKey(gpluskey);
    sb.apiSecret(gplussecret);
    sb.scope("email");
    String callBackUrl = Page.getCurrent().getLocation().toString();
    if(callBackUrl.contains("#")) {
        callBackUrl = callBackUrl.substring(0, callBackUrl.indexOf("#"));
    }
    sb.callback(callBackUrl);
    return sb.build();
}

Via the fully configured service class, we will get the URL where the user can log in and grant application an access to his/her data. To forward the user there, I’m using a separate link so that the user doesn’t think that he/she accidentally ended up there.

service = createService();
String url = service.getAuthorizationUrl(null);

gplusLoginButton = new Link("Login with Google", new ExternalResource(url));
gplusLoginButton.addStyleName(ValoTheme.LINK_LARGE);

The OAuth 2 magic

When the user grants (or rejects) an access to his/her email address, he returns to our application with special parameters. To read those, we register a session scoped parameter handler to our Vaadin application. Using a code passed as a request parameter, we create a Verifier instance that is our “passport” to OAuth protected services that Google provides.

Using the Verifier we can now use the Google+ service to get general information about the user and specify the email address we are interested in this case. The payload from the Google+ API is in JSON format, so I wrote very simple wrapper classes and parsed the response using Gson. The next step is then to pass the email address to UserSession using a login method.

Finally, we’ll just need to make some small cleanup. Close the window, remove the OAuth return URL handler and, to give a final touch, we’ll redirect the user to a clean address without the OAuth request parameters. The full request handler method in the example looks like this:

@Override
public boolean handleRequest(VaadinSession session, VaadinRequest request,
        VaadinResponse response) throws IOException {
    if (request.getParameter("code") != null) {
        String code = request.getParameter("code");
        Verifier v = new Verifier(code);
        Token t = service.getAccessToken(null, v);

        OAuthRequest r = new OAuthRequest(Verb.GET,
                "https://www.googleapis.com/plus/v1/people/me");
        service.signRequest(t, r);
        Response resp = r.send();

        GooglePlusAnswer answer = new Gson().fromJson(resp.getBody(),
                GooglePlusAnswer.class);

        userSession.login(answer.emails[0].value, answer.displayName);

        close();
        VaadinSession.getCurrent().removeRequestHandler(this);

        ((VaadinServletResponse) response).getHttpServletResponse().
                sendRedirect(redirectUrl);
        return true;
    }

    return false;
}

Hooray! We can now identify the user and provide the correct user-specific data - without nasty registration or low-quality passwords by the end user. Although OAuth 2 is not necessarily the simplest way to tackle authentication, the procedure is finally pretty straightforward. The end user can skip registration and password hassles, and you don’t need to worry about the security of your password hashing algorithms.

If you want to try OAuth 2 sign-in using my example application, you just need to create an application in Google Developer Console and create a “Client ID” in the “APIs & Auth->Credentials” section. Also, remember to register a proper “Redirect URL” for your development server (for example http://localhost:8080/invoicer/). Once you have placed the “Client ID” and its “Client secret” to the apache-deltaspike.properties file (or to pom.xml) you can just run the app locally and start playing around with it.

Check out the full example app on GitHub

 

Learn more about Vaadin
Discover the easiest way to build web apps in Java

Read more
Download our free guide to the Future of Web Apps

Matti Tahvonen
Matti Tahvonen
Matti Tahvonen has a long history in Vaadin R&D: developing the core framework from the dark ages of pure JS client side to the GWT era and creating number of official and unofficial Vaadin add-ons. His current responsibility is to keep you up to date with latest and greatest Vaadin related technologies. You can follow him on Twitter – @MattiTahvonen
Other posts by Matti Tahvonen