How to get User Information with OAuth2 in a GWT and Google AppEngine Java Application?


Facebook Twitter More...

By Markus Sprunck; Revision: 1.5; Status: final; Last Content Change: Apr 16, 2013;

In the following article the use of OAuth2 in a GWT and Google AppEngine Java application to get user information like name, gender, picture, nickname, e-mail is described. 

The following example application http://oaae-sample.appspot.com demonstrates the implementation of login and display the name and picture of Google account at the right top corner of the window.

Expected Result

In picture 1 the name of the logged on user name and profile picture have been marked in red. 

Picture 1: Screen shot of OAuthAppEngineSample.

Get a Web Applications Starter Project

If you are already familiar with GWT & Google AppEngine, you can skip this section and jump directly to the next. An excellent source for learning the basics are the Google sites. At the end of this tutorial you can find some useful links. 

The next 10 steps are easy and you can do it in 5 minutes. You just need the Google Plugin for Eclipse
(see Using the Google Plugin for Eclipse) and an account for Google AppEngine. I recommend to use Eclipse 3.7 Indigo.

1) Create a web project in Eclipse with the name OAuthAppEngineSample (if you use the same name the next codes changes are easier to do). 



2) Expected result in Eclipse



3) Now, create a new application on Google App Engine. This is necessary to deploy the application. 



4) Create a new application on Google App Engine Result (success)



5) Deploy to AppEngine 
- select project and
- click to [App Engine project settings...]



6) App Engine project settings
- select Application ID



7) Deploy to AppEngine



8 ) Now you should have a version 1 in your AppEngine (check http://appengine.google.com)



9) Test the success (use the link without version number and point) 



10) Klick on button [Send] and check the dialog box. Now you have an running "Hello, GWT User!" application on Google AppEngine.




OAuth2 in Google APIs Console

1) Create a client ID in the Google APIs Console (open http://code.google.com/apis/console and click on menu API Access)


In this case the created id was:

Client ID: 808558447093-1fa4phmdplj0lc7ug6n988u4gfageph8.apps.googleusercontent.com
Email address: 808558447093-1fa4phmdplj0lc7ug6n988u4gfageph8@developer.gserviceaccount.com
Client secret: N61dctCTs5yEdK1cVaoRJ0Kv
Redirect URIs: http://oaae-sample.appspot.com/oauthappenginesample/oauthWindow.html 
(be sure that this path is correct, the default value may be different)
JavaScript origins: http://oaae-sample.appspot.com

Changes of the OAuthAppEngineSample

 TODO #01: define css style for new login panel

// File #1: OAuthAppEngineSample.css
/** Add css rules here for your application. */
/** Example rules used by the template application (remove for your app) */
h1 {
font-size: 2em;
font-weight: bold;
color: #777777;
margin: 40px 0px 70px;
text-align: center;
}

.sendButton {
display: block;
font-size: 16pt;
}

/** Most GWT widgets already have a style name defined */
.gwt-DialogBox {
width: 400px;
}

.dialogVPanel {
margin: 5px;
}

.serverResponseLabelError {
color: red;
}

/** Set ids using widget.getElement().setId("idOfElement") */
#closeButton {
margin: 15px 6px 6px;
}

/** TODO #01: define css style for login panel | start */
.login-banner {
background-color: #2D2D2D;
border-bottom: 1px solid #000;
color: #FFF;
cursor: auto;
font: 11px/27px Arial, sans-serif;
font-weight: cursiv;
height: 31px;
left: 0;
opacity: 1;
position: absolute;
top: 0;
width: 100%;
z-index: 990;
}

.login-area,.login-area:hover,.login-area:visited {
border: solid #2D2D2D;
border-width: 4px;
font-size: 13pt;
font-weight: 300;
color: #FFF;
text-decoration: none;
}
/** TODO #01:> end */

 TODO #02: insert login panel in main page

// File #2: OAuthAppEngineSample.html
<!doctype html>
<!-- The DOCTYPE declaration above will set the -->
<!-- browser's rendering engine into -->
<!-- "Standards Mode". Replacing this declaration -->
<!-- with a "Quirks Mode" doctype is not supported. -->

<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">

    <!-- -->
    <!-- Consider inlining CSS to reduce the number of requested files -->
    <!-- -->
    <link type="text/css" rel="stylesheet" href="OAuthAppEngineSample.css">

    <!-- -->
    <!-- Any title is fine -->
    <!-- -->
    <title>oauth2-google-appengine-example</title>
    
    <!-- -->
    <!-- This script loads your compiled module. -->
    <!-- If you add any GWT meta tags, they must -->
    <!-- be added before this line. -->
    <!-- -->
    <script type="text/javascript" language="javascript" src="oauthappenginesample/oauthappenginesample.nocache.js"></script>
  </head>

  <!-- -->
  <!-- The body can have arbitrary html, or -->
  <!-- you can leave the body empty if you want -->
  <!-- to create a completely dynamic UI. -->
  <!-- -->
  <body>
  
      <!-- OPTIONAL: include this if you want history support -->
    <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
    
    <!-- RECOMMENDED if your web app will not function without JavaScript enabled -->
    <noscript>
      <div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
        Your web browser must have JavaScript enabled
        in order for this application to display correctly.
      </div>
    </noscript>
    
    <!-- TODO #02: insert login panel | start -->
  <div class="login-banner" align="right" id="loginPanelContainer"></div>
<!-- TODO #02:> end -->

<br/>
    <table align="center">
      <tr>
        <td>
         <h2 align="center">OAuth2 Google AppEngine Example from Software Engineering Candies</h2>
         <h2 align="center">
         <a href="http://www.sw-engineering-candies.com/blog-1/howtogetuserinformationwithoauth2inagwtandgoogleappenginejavaapplication">
         How to get User Information with OAuth2 in a GWT and Google AppEngine Java Application?
         </a></h2>
        </td>
      </tr>
    </table>

  <br/>
    <table align="center">
      <tr>
        <td colspan="2" style="font-weight:bold;">Please enter your name:</td>
      </tr>
      <tr>
        <td id="nameFieldContainer"></td>
        <td id="sendButtonContainer"></td>
      </tr>
      <tr>
        <td colspan="2" style="color:red;" id="errorLabelContainer"></td>
      </tr>
    </table>
  </body>
</html>

 TODO #03: inherit the OAuth2 lib

// File #3: OAuthAppEngineSample.gwt.xml
<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='oauthappenginesample'>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name='com.google.gwt.user.User' />

<!-- Inherit the default GWT style sheet. You can change -->
<!-- the theme of your GWT application by uncommenting -->
<!-- any one of the following lines. -->
<inherits name='com.google.gwt.user.theme.clean.Clean' />
<!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/> -->
<!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
<!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/> -->

<!-- TODO #03: inherit the OAuth2 lib -->
<inherits name="com.google.api.gwt.oauth2.OAuth2" />
<!-- TODO #03:> end -->

<!-- Other module inherits -->

<!-- Specify the app entry point class. -->
<entry-point class='com.sw_engineering_candies.oauth2.client.OAuthAppEngineSample' />

<!-- Specify the paths for translatable code -->
<source path='client' />
<source path='shared' />

</module>

 TODO #04: manage libraries and build path

- download the following libraries :
OAuthAppEngineSample/war/WEB-INF/lib/google-api-client-1.6.0-beta.jar
        (e.g. google-plus-java-starter)
OAuthAppEngineSample/war/WEB-INF/lib/google-oauth-client-1.5.0-beta.jar
        (e.g. google-api-java-client)
OAuthAppEngineSample/war/WEB-INF/lib/gwt-oauth2-0.2-alpha.jar
        (e.g. gwt-oauth2)
OAuthAppEngineSample/war/WEB-INF/lib/jackson-core-asl-1.9.1.jar
        (e.g. Jarvana - Maven Repository Search Engine)
- insert files into project and 
- add them to build path

 TODO #05: add constants for OAuth2 (don't forget to update GOOGLE_CLIENT_ID)

 TODO #06: define controls for login

 TODO #07: add helper methods for Login, Logout and AuthRequest

 TODO #08: create login controls

// File #4: OAuthAppEngineSample.java
package com.sw_engineering_candies.oauth2.client;

import com.sw_engineering_candies.oauth2.shared.FieldVerifier;
import com.sw_engineering_candies.oauth2.shared.LoginInfo;
import com.google.gwt.core.client.Callback;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.dom.client.LoadEvent;
import com.google.gwt.event.dom.client.LoadHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

import com.google.api.gwt.oauth2.client.Auth;
import com.google.api.gwt.oauth2.client.AuthRequest;

/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class OAuthAppEngineSample implements EntryPoint {

// TODO #05: add constants for OAuth2 (don't forget to update GOOGLE_CLIENT_ID)
private static final Auth AUTH = Auth.get();
private static final String GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/auth";
private static final String GOOGLE_CLIENT_ID = "808558447093-1fa4phmdplj0lc7ug6n988u4gfageph8.apps.googleusercontent.com";
private static final String PLUS_ME_SCOPE = "https://www.googleapis.com/auth/userinfo.profile";
// TODO #05:> end

// TODO #06: define controls for login
private final HorizontalPanel loginPanel = new HorizontalPanel();
private final Anchor signInLink = new Anchor("");
private final Image loginImage = new Image();
private final TextBox nameField = new TextBox();
// TODO #06:> end

/**
* The message displayed to the user when the server cannot be reached or returns an error.
*/
private static final String SERVER_ERROR = "An error occurred while "
+ "attempting to contact the server. Please check your network "
+ "connection and try again.";

/**
* Create a remote service proxy to talk to the server-side Greeting service.
*/
private final GreetingServiceAsync greetingService = GWT.create(GreetingService.class);

// TODO #07: add helper methods for Login, Logout and AuthRequest

private void loadLogin(final LoginInfo loginInfo) {
signInLink.setHref(loginInfo.getLoginUrl());
signInLink.setText("Please, sign in with your Google Account");
signInLink.setTitle("Sign in");
}

private void loadLogout(final LoginInfo loginInfo) {
signInLink.setHref(loginInfo.getLogoutUrl());
signInLink.setText(loginInfo.getName());
signInLink.setTitle("Sign out");
}

private void addGoogleAuthHelper() {
final AuthRequest req = new AuthRequest(GOOGLE_AUTH_URL, GOOGLE_CLIENT_ID)
.withScopes(PLUS_ME_SCOPE);
AUTH.login(req, new Callback<String, Throwable>() {
@Override
public void onSuccess(final String token) {

if (!token.isEmpty()) {
greetingService.loginDetails(token, new AsyncCallback<LoginInfo>() {
@Override
public void onFailure(final Throwable caught) {
GWT.log("loginDetails -> onFailure");
}

@Override
public void onSuccess(final LoginInfo loginInfo) {
signInLink.setText(loginInfo.getName());
nameField.setText(loginInfo.getName());
signInLink.setStyleName("login-area");
loginImage.setUrl(loginInfo.getPictureUrl());
loginImage.setVisible(false);
loginPanel.add(loginImage);
loginImage.addLoadHandler(new LoadHandler() {
@Override
public void onLoad(final LoadEvent event) {
final int newWidth = 24;
final com.google.gwt.dom.client.Element element = event
.getRelativeElement();
if (element.equals(loginImage.getElement())) {
final int originalHeight = loginImage.getOffsetHeight();
final int originalWidth = loginImage.getOffsetWidth();
if (originalHeight > originalWidth) {
loginImage.setHeight(newWidth + "px");
} else {
loginImage.setWidth(newWidth + "px");
}
loginImage.setVisible(true);
}
}
});
}
});
}
}

@Override
public void onFailure(final Throwable caught) {
GWT.log("Error -> loginDetails\n" + caught.getMessage());
}
});
}

// TODO #07:> end

/**
* This is the entry point method.
*/
@Override
public void onModuleLoad() {


final Button sendButton = new Button("Send");
final Label errorLabel = new Label();

// We can add style names to widgets
sendButton.addStyleName("sendButton");

// Add the nameField and sendButton to the RootPanel
// Use RootPanel.get() to get the entire body element
RootPanel.get("nameFieldContainer").add(nameField);
RootPanel.get("sendButtonContainer").add(sendButton);
RootPanel.get("errorLabelContainer").add(errorLabel);

// Focus the cursor on the name field when the app loads
nameField.setFocus(true);
nameField.selectAll();

// Create the popup dialog box
final DialogBox dialogBox = new DialogBox();
dialogBox.setText("Remote Procedure Call");
dialogBox.setAnimationEnabled(true);
final Button closeButton = new Button("Close");
// We can set the id of a widget by accessing its Element
closeButton.getElement().setId("closeButton");
final Label textToServerLabel = new Label();
final HTML serverResponseLabel = new HTML();
VerticalPanel dialogVPanel = new VerticalPanel();
dialogVPanel.addStyleName("dialogVPanel");
dialogVPanel.add(new HTML("<b>Sending name to the server:</b>"));
dialogVPanel.add(textToServerLabel);
dialogVPanel.add(new HTML("<br><b>Server replies:</b>"));
dialogVPanel.add(serverResponseLabel);
dialogVPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
dialogVPanel.add(closeButton);
dialogBox.setWidget(dialogVPanel);

// Add a handler to close the DialogBox
closeButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
dialogBox.hide();
sendButton.setEnabled(true);
sendButton.setFocus(true);
}
});

// Create a handler for the sendButton and nameField
class MyHandler implements ClickHandler, KeyUpHandler {
/**
* Fired when the user clicks on the sendButton.
*/
@Override
public void onClick(ClickEvent event) {
sendNameToServer();
}

/**
* Fired when the user types in the nameField.
*/
@Override
public void onKeyUp(KeyUpEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
sendNameToServer();
}
}

/**
* Send the name from the nameField to the server and wait for a response.
*/
private void sendNameToServer() {
// First, we validate the input.
errorLabel.setText("");
String textToServer = nameField.getText();
if (!FieldVerifier.isValidName(textToServer)) {
errorLabel.setText("Please enter at least four characters");
return;
}

// Then, we send the input to the server.
sendButton.setEnabled(false);
textToServerLabel.setText(textToServer);
serverResponseLabel.setText("");
greetingService.greetServer(textToServer, new AsyncCallback<String>() {
@Override
public void onFailure(Throwable caught) {
// Show the RPC error message to the user
dialogBox.setText("Remote Procedure Call - Failure");
serverResponseLabel.addStyleName("serverResponseLabelError");
serverResponseLabel.setHTML(SERVER_ERROR);
dialogBox.center();
closeButton.setFocus(true);
}

@Override
public void onSuccess(String result) {
dialogBox.setText("Remote Procedure Call");
serverResponseLabel.removeStyleName("serverResponseLabelError");
serverResponseLabel.setHTML(result);
dialogBox.center();
closeButton.setFocus(true);
}
});
}
}

// TODO #08: create login controls
sendButton.setEnabled(false);
nameField.setEnabled(false);

signInLink.getElement().setClassName("login-area");
signInLink.setTitle("sign out");
loginImage.getElement().setClassName("login-area");
loginPanel.add(signInLink);
RootPanel.get("loginPanelContainer").add(loginPanel);
final StringBuilder userEmail = new StringBuilder();
greetingService.login(GWT.getHostPageBaseURL(), new AsyncCallback<LoginInfo>() {
@Override
public void onFailure(final Throwable caught) {
GWT.log("login -> onFailure");
}

@Override
public void onSuccess(final LoginInfo result) {
if (result.getName() != null && !result.getName().isEmpty()) {
addGoogleAuthHelper();
loadLogout(result);
sendButton.setEnabled(true);
nameField.setEnabled(true);
} else {
loadLogin(result);
}
userEmail.append(result.getEmailAddress());
}
});
// TODO #08:> end


// Add a handler to send the name to the server
MyHandler handler = new MyHandler();
sendButton.addClickHandler(handler);
nameField.addKeyUpHandler(handler);
}
}

 TODO #09: start create login helper methods in service interface

// File #5: GreetingService.java
package com.sw_engineering_candies.oauth2.client;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import com.sw_engineering_candies.oauth2.shared.LoginInfo;

/**
* The client side stub for the RPC service.
*/
@RemoteServiceRelativePath("greet")
public interface GreetingService extends RemoteService {

String greetServer(String name) throws IllegalArgumentException;

// TODO #09: start create login helper methods in service interface
String getUserEmail(String token);

LoginInfo login(String requestUri);

LoginInfo loginDetails(String token);
// TODO #09:> end
}

 TODO #10: create login helper methods in service asynchronous interface

// File #6: GreetingServiceAsync.java
package com.sw_engineering_candies.oauth2.client;

import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sw_engineering_candies.oauth2.shared.LoginInfo;

/**
* The async counterpart of <code>GreetingService</code>.
*/
public interface GreetingServiceAsync {

void greetServer(String input, AsyncCallback<String> callback) throws IllegalArgumentException;

// TODO #10: create login helper methods in service asynchronous interface
void getUserEmail(String token, AsyncCallback<String> callback);

void login(String requestUri, AsyncCallback<LoginInfo> asyncCallback);

void loginDetails(String token, AsyncCallback<LoginInfo> asyncCallback);
// TODO #10:> end

}

 TODO #11: implement login helper methods in service implementation

// File #7: GreetingServiceImpl.java
package com.sw_engineering_candies.oauth2.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import com.sw_engineering_candies.oauth2.client.GreetingService;
import com.sw_engineering_candies.oauth2.shared.FieldVerifier;
import com.sw_engineering_candies.oauth2.shared.LoginInfo;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import java.util.logging.Level;
import java.util.logging.Logger;
import java.net.URL;
import java.net.URLConnection;

import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;

/**
* The server side implementation of the RPC service.
*/
@SuppressWarnings("serial")
public class GreetingServiceImpl extends RemoteServiceServlet implements GreetingService {

private static Logger log = Logger.getLogger(GreetingServiceImpl.class.getCanonicalName());

@Override
public String greetServer(String input) throws IllegalArgumentException {
// Verify that the input is valid.
if (!FieldVerifier.isValidName(input)) {
// If the input is not valid, throw an IllegalArgumentException back to
// the client.
throw new IllegalArgumentException("Name must be at least 4 characters long");
}

String serverInfo = getServletContext().getServerInfo();
String userAgent = getThreadLocalRequest().getHeader("User-Agent");

// Escape data from the client to avoid cross-site script vulnerabilities.
input = escapeHtml(input);
userAgent = escapeHtml(userAgent);

return "Hello, " + input + "!<br><br>I am running " + serverInfo + ".<br><br>It looks like you are using:<br>"
+ userAgent;
}

/**
* Escape an html string. Escaping data received from the client helps to
* prevent cross-site script vulnerabilities.
*
* @param html the html string to escape
* @return the escaped string
*/
private String escapeHtml(String html) {
if (html == null) {
return null;
}
return html.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
}

// TODO #11: implement login helper methods in service implementation

@Override
public String getUserEmail(final String token) {
final UserService userService = UserServiceFactory.getUserService();
final User user = userService.getCurrentUser();
if (null != user) {
return user.getEmail();
} else {
return "noreply@sample.com";
}
}

@Override
public LoginInfo login(final String requestUri) {
final UserService userService = UserServiceFactory.getUserService();
final User user = userService.getCurrentUser();
final LoginInfo loginInfo = new LoginInfo();
if (user != null) {
loginInfo.setLoggedIn(true);
loginInfo.setName(user.getEmail());
loginInfo.setLogoutUrl(userService.createLogoutURL(requestUri));
} else {
loginInfo.setLoggedIn(false);
loginInfo.setLoginUrl(userService.createLoginURL(requestUri));
}
return loginInfo;
}

@Override
public LoginInfo loginDetails(final String token) {
String url = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=" + token;

final StringBuffer r = new StringBuffer();
try {
final URL u = new URL(url);
final URLConnection uc = u.openConnection();
final int end = 1000;
InputStreamReader isr = null;
BufferedReader br = null;
try {
isr = new InputStreamReader(uc.getInputStream());
br = new BufferedReader(isr);
final int chk = 0;
while ((url = br.readLine()) != null) {
if ((chk >= 0) && ((chk < end))) {
r.append(url).append('\n');
}
}
} catch (final java.net.ConnectException cex) {
r.append(cex.getMessage());
} catch (final Exception ex) {
log.log(Level.SEVERE, ex.getMessage());
} finally {
try {
br.close();
} catch (final Exception ex) {
log.log(Level.SEVERE, ex.getMessage());
}
}
} catch (final Exception e) {
log.log(Level.SEVERE, e.getMessage());
}

final LoginInfo loginInfo = new LoginInfo();
try {
final JsonFactory f = new JsonFactory();
JsonParser jp;
jp = f.createJsonParser(r.toString());
jp.nextToken();
while (jp.nextToken() != JsonToken.END_OBJECT) {
final String fieldname = jp.getCurrentName();
jp.nextToken();
if ("picture".equals(fieldname)) {
loginInfo.setPictureUrl(jp.getText());
} else if ("name".equals(fieldname)) {
loginInfo.setName(jp.getText());
} else if ("email".equals(fieldname)) {
loginInfo.setEmailAddress(jp.getText());
}
}
} catch (final JsonParseException e) {
log.log(Level.SEVERE, e.getMessage());
} catch (final IOException e) {
log.log(Level.SEVERE, e.getMessage());
}
return loginInfo;
}

// TODO #11:> end

}

 TODO #12: add LoginInfo helper class

// File #9: LoginInfo.java
// TODO #12: add LoginInfo helper class

package com.sw_engineering_candies.oauth2.shared;

import java.io.Serializable;

public class LoginInfo implements Serializable {

private static final long serialVersionUID = 1L;

private boolean loggedIn = false;

private String loginUrl;

private String logoutUrl;

private String emailAddress;

private String nickname;

private String pictureUrl;

public boolean isLoggedIn() {
return loggedIn;
}

public void setLoggedIn(final boolean loggedIn) {
this.loggedIn = loggedIn;
}

public String getLoginUrl() {
return loginUrl;
}

public void setLoginUrl(final String loginUrl) {
this.loginUrl = loginUrl;
}

public String getLogoutUrl() {
return logoutUrl;
}

public void setLogoutUrl(final String logoutUrl) {
this.logoutUrl = logoutUrl;
}

public String getEmailAddress() {
return emailAddress;
}

public void setEmailAddress(final String emailAddress) {
this.emailAddress = emailAddress;
}

public String getName() {
return nickname;
}

public void setName(final String nickname) {
this.nickname = nickname;
}

public void setPictureUrl(final String pictureUrl) {
this.pictureUrl = pictureUrl;

}

public String getPictureUrl() {
return pictureUrl;
}

}
// TODO #12:> end


Now you can build and deploy the application to the Google AppEngine.

Test Expected Result

1) Press sign in link in the top dark bar.

2) Agree access. You can withdraw the access rights in Google Dashboard (see link below).

3) Check result. The name and picture should appear at the right top corner.

Please, do not hesitate to contact me if you have any ideas for improvement and/or you find a bug in the sample code.

Further Reading

1) Google AppEngine (Introduction); http://developers.google.com/appengine/docs/java/gettingstarted
2) Using the Google Plugin for Eclipse: http://developers.google.com/appengine/docs/java/tools/eclipse 
3) Google Dashboard (Authorized Access to your Google Account); http://www.google.com/dashboard
4) Using OAuth 2.0 to Access Google APIs; http://developers.google.com/accounts/docs/OAuth2
5) Google AppEngine (Sign up); http://developers.google.com/appengine

Find Code on GitHub

Change History

 Revision  Date  Author  Description
 1.0  Mar 30, 2012  Markus Sprunck   created
 1.1  Jul 31, 2012  Markus Sprunck  enhancements
 1.2  Aug 5, 2012  Markus Sprunck  bugfix - many thanks for the discussion at prog.hu and personal feedback
 from Prém József.
 1.3  Aug 18, 2012  Markus Sprunck  improved layout for tablets
 1.4      Feb 10, 2013   Markus Sprunck  input field and button disabled before login and some fixed typos
 1.5  Apr 16, 2013  Markus Sprunck   source code now on GitHub

Google+ Comments

You may press the +1 button to share and/or comment