Google Cloud Endpoints Tutorial – Part 6

Welcome to Part 6 of the Google Cloud Endpoints Tutorial.

The full series:

  • Part 1 : We looked at writing a Google Cloud Endpoints class manually by using the various annotations and Exception classes that are available. We create a Quotes API that provided a JSON + REST based interface to manage Quotes (add, modify, delete and retrieve quotes).
  • Part 2 : We generated the Google Cloud Endpoints class from a JDO Annotated Entity class by using the Code Generation tools provided in the library.
  • Part 3 : Generated the Cloud Endpoints Client Library for Android and wrote an Android application that invokes the Endpoints API.
  • Part 4: We wrote a JavaScript client for our Endpoints API.
  • Part 5: Securing our API
  • Part 6: Calling a Secured API from a JavaScript client.
  • Part 7 : Calling a Secured API from an Android client.

I have also published a list of Cloud Endpoints Tips:

  1. Check Endpoint Deployment Status
  2. Throw the Right Exception Classes
  3. Understand Injected Types
  4. Understand @API and @APIMethod Annotations
  5. Using Cursor and Limit parameters
  6. The @APIResourceProperty Annotation

In this episode

So far in this series, we looked at writing a Quote API and in the last episode, we introduced how to secure your API methods so that only authorized clients can invoke the methods. We secured the insertQuote method in the last episode and in this episode, we are going to see how to make secure calls from our JavaScript client.

Keep in mind that we had written a JavaScript client for our Endpoints API earlier in Episode 4, so please take a look at that first.

What do you need ?

  • You have a working development environment for Google App Engine. This includes the Google Eclipse plugin.
  • The API Project 2 (Quotes Endpoint Project) loaded in your Development Environment. This is the same as the previous episode, except that we will be focusing on the apitest.html , which is our API client.

My Development Environment

This remains the same, no changes at all. My development environment is given below:

  • Eclipse Juno
  • Google Eclipse plugin with App Engine SDK 1.8.8.
  • Mac + Windows machine (I kept switching from one to another, to keep everyone happy ;-))

Web Client in Action

Let us first try to understand what we are going to create here by seeing the application and security in action.

I am accessing the client at http://mybackendapi.appspot.com/apitest.html. I have currently logged out from all of my Google Accounts.

When I access the above page, I get the following page:

Screen Shot 2014-02-15 at 2.45.24 PM

Notice the Login button shown above. This button is shown if there was no Google Account that was already logged in. If the User was logged in, this button would be invisible and instead we would be having a Welcome message.

Now, we will not yet click on the Login button. Instead we will attempt to insert a new Quote without logging in and verify if the insertQuote method is indeed secured or not. We enter test values in the Author Name and Quote as shown below and click on the Insert Quote button. This will bring up a popup as shown below. In fact this is the response that we have simply displayed and which came from the Endpoints API HTTP Response:

Screen Shot 2014-02-15 at 2.45.46 PM

In the JavaScript code, I log out the response to the console and which you can see below:

Screen Shot 2014-02-15 at 2.45.57 PM

Now, I click on Login and go through the standard OAuth dance, where I choose a Google Account to log in with, give my credentials and then authorize the application. If all is well, I am logged into our client now and we retrieve the User Name from the OAuth API and display a welcome sign on the top, as shown below:

Screen Shot 2014-02-15 at 2.43.57 PM

Now, I can give my sample values for the Author Name and Quote and click on Insert Quote. 

Screen Shot 2014-02-15 at 2.44.37 PM

The record will get inserted and when I do a List Quotes , I will see the new record that I added:Screen Shot 2014-02-15 at 2.44.57 PM

Let us discuss the code now.

Web Client Id

If you recollect, in the earlier episode, we had visit the Google Cloud Console for our project and create the OAuth Client Id. A screenshot of the Web Client Id is shown below.

Screen Shot 2014-02-14 at 8.45.01 PM

Additionally, we had updated the @APIMethod for insertQuote and provided the clientIds, that included the Web Client Id and then deployed the API. 

JavaScript Client

The entire source code for apitest.html is shown below. The code snippets for Login functionality has been borrowed from the sample code provided in the official document by Google.

Let us look at the main points. Parts of the code should be familiar if you have worked with the JavaScript client that was introduced in Part 4 of this series.

  • We have added a Login button to the User Interface.
    <div id=”login”>
    <input id=”loginButton” type=”button” value=”Login”/>
    </div>
  • As covered in an earlier episode, we load the Client API and once the API is loaded, our init method is invoked.
  • In our init method, we are loading two APIs now : the Quote Endpoint API as we have done earlier and the OAuth API.
  • Once both the APIs are successfully loaded, we are invoking the signin method. To the signin method, we are providing two parameters : an immediate mode parameter whose value is set to true and a callback function : handleAuth.
  • In the signin method, we invoke the gapi.auth.authorize method. To that method, we pass the client Id, scope, immediate mode and the callback (handleAuth). Notice that we have initialized the client Id and scope values in the code and they are the same values as the ones we have created via the Google Cloud Console OAuth New Client creation page. These must match for the authentication/authorization to succeed.
  • In the handleAuth method, we get the current User Object. If the User is found with no errors, then we hide the Login button and display the Welcome message. If the User is not found, the Login button is made visible. This is what happens when our page is loaded i.e. Login button is shown or not shown depending on whether the user is logged in or not. This is also known as the immediate mode.
  • Now, if the Login button is shown i.e. authorization still has to be done, then we have a handler for our Login Button as shown below:
    document.getElementById(‘loginButton’).onclick = function() {
             signin(false,handleAuth);
     }
  • If Login Button is clicked, the signin method is called again with the immediate mode set to false and the callback method as the same one i.e. handleAuth. This will invoke the entire Google Login popup and you go through with the Authentication and Authorization cycle.
  • The insertQuote method is slightly modified to display the error in case there is a problem executing the gapi.client.quoteendpoint.insertQuote method.

Project Source Code

The source code for the MyAPIProject2 is available in Github. You can download the entire source code over here.

Hope you liked this episode of the Google Cloud Endpoints tutorial. The next episode will cover making secured API calls from an Android client.

About these ads

23 thoughts on “Google Cloud Endpoints Tutorial – Part 6

  1. Hmm, I’m getting an origin mismatch when I attempt to login.

    Google
    Error: origin_mismatch
    Request Details
    cookie_policy_enforce=false
    scope=https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/plus.me
    response_type=token
    access_type=online
    redirect_uri=postmessage
    proxy=oauth2relay787498190
    include_granted_scopes=true
    origin=http://mybackendapi.appspot.com
    state=775275838|0.3985433865
    display=page
    client_id=756161739003-0l5c7ptti2j42l28j5anijr5mukks835.apps.googleusercontent.com
    authuser=0

      1. Hi Romin,

        Thank you very much for your tutorials. I’m a beginner. I have been following these cloud endpoint tutorials of yours. I downloaded your source project at https://github.com/rominirani/MyAPIProject2
        then deployed it on my own app engine instead of using your ‘mybackendapi.appspot.com/apitest.html’, as an exercise. Everything has been working fine until now that I hit the same error related to origin. May I ask how you fixed the origin error on your mybackendapi App engine?

        Thank you again,

      2. Hi JZ — Thanks for your feedback.

        For the Origin issue — you will need to carefully check the following:
        1) In Google Cloud Console for your project, when you do the OAuth settings, note down the origins that you are setting carefully. In the blog post that I have given, I used 2 of them i.e. localhost and the actual appspot.com domain. This was done so that I can test both locally and also when it is deployed on the appspot.com domain.

        When you hit the URL in your browser, ensure that the origin is the same. For e.g. if your appid is myappid, then in your browser, you would hit something like https://appid.appspot.com/index.html, then you will need to have the origin mentioned as https://appid.appspot.com. Even mistakes like https vs http will result in an origin mismatch. Similarly, if you are testing on local, you might hit http://localhost:8888/index.html, so in this case, ensure that http://localhost:8888 is in the origin list also. Keep each origin on a separate line in the OAuth settings. Hope this helps. I believe it is just a matter of checking carefully.

  2. Romin, I’ve been following your guides and they helped me a lot.
    However, I’m using GWT instead of just HTML. So it’s a little bit hard dealing with Javascript inside Java code.
    I’ve tried to list Quotes using JSNI in GWT, however, I simply can’t get the JSON response that comes from the API.
    Do you have any experience working with GWT and JSNI?

  3. Great. Thank you, Romin! will double check. It’s hard to find good tutorials on google cloud end point. Really appreciate your good work :-)

  4. Thanks to your tutorial i got endpoints finally work. But i have had issues with the oauth2 part.
    There are changes within the oauth2 interface ? (since Eclipse Google Plugin 1.9.x ?).
    We now need to follow exactly the tictactoe example, otherwise we get a
    server error “getCurrentUser: AccessToken; scope not allowed” and the “User is invalid”
    return.
    Solution: get the “id_token” and use it as “access_token” , very strange !

    var RESPONSE_TYPE = ‘token id_token’ ;

    function signin(mode, callback) {
    gapi.auth.authorize({client_id: CLIENT_ID,scope: SCOPES, immediate: mode, response_type:RESPONSE_TYPE },callback);
    }

    function handleAuth() {
    var request = gapi.client.oauth2.userinfo.get();
    request.execute(function(resp) {
    console.log( resp ) ;
    if (!resp.code) {
    // User is signed in, so hide the button
    console.log( “User is: ” + resp.email ) ;
    token=gapi.auth.getToken() ;
    console.log( “Access Token is now” + token.id_token + “exp ” + token.expires_in );
    token.access_token = token.id_token ; // !!!!!!!!!!!!!!!!
    gapi.auth.setToken(token) ;
    document.getElementById(‘loginButton’).style.visibility = ‘hidden’;
    document.getElementById(‘login’).innerText = ‘Welcome ‘ + resp.name;
    // visualize your data now
    // showData() ;
    }
    else {
    console.log( “Login required” ) ;
    document.getElementById(‘loginButton’).style.visibility = ”;
    }
    });
    }

  5. Great. Thank you, Romin. Really appreciate your good work. Is it possible to use my own authentication or Facebook (oauth2) to authenticate the API calls?

    1. Benjamin – thank you for the feedback. Much appreciated.

      You can definitely roll your own security to authenticate the API calls, though that will require a lot more work. I think it is one of the long standing requirements of the developer community, when it comes to Google Cloud Endpoints. What I have typically seen people do for custom authentication is using tokens that are predetermined, sent during the requests and then the Server side authenticates your token. You will need to write the stuff to issue tokens, manage them, expire them, etc. But this is definitely one way.

  6. Hi Romin,

    I wanted to accept JSON array as an input to my endpoint. eg. [ { "name": "Ram","event": "processed" },
    {"name": "Raj", "event": "click" }] . Tried some of the possible ways, cloud endpoints are not supporting arrays or any array related types to use. I tried to declare list in a separate class and tried to access through it but it accepts as JSONObject not as a JSONArray. I did not find any workaround for this. Don’t know whether this is the right place to post this question. Thanks in advance.

    Thanks,
    Arun

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s