Sending an authenticated request from a JavaScript application

This page describes how to send an authenticated request from a JavaScript application running locally to a REST API created by using Cloud Endpoints Frameworks. The JavaScript application shows how to use Google Sign-In and how to send a Google ID token in the request to authenticate the user. When the JavaScript application sends the request, Endpoints Frameworks authenticates the user before passing the request to the backend code that is running on the App Engine standard environment.

Prerequisites

To run the sample JavaScript application:

  • Find the Google Cloud Platform (GCP) project ID that you created for the sample API because you need to add it to the sample JavaScript code. If you need help finding your project ID, see Listing projects.

  • You need a web server on your local computer to serve the sample index.html file that contains the JavaScript code. This page includes steps for running SimpleHTTPServer, which comes with Python 2.7, but you can use any web server.

Download the sample JavaScript client code

  1. Clone the sample to your local machine:

    git clone https://github.com/GoogleCloudPlatform/web-docs-samples
    
  2. Change to the directory that contains the JavaScript client:

    cd web-docs-samples/endpoints-frameworks
    

Creating OAuth 2.0 client IDs

To set up the sample for authentication, you need to configure an OAuth 2.0 client ID in the sample JavaScript code and in the backend code. The JavaScript app uses the client ID to obtain a Google ID token from Google's OAuth 2.0 server and sends the Google ID token in the request. Endpoints Frameworks uses the client ID to authenticate the ID token that the JavaScript app sent in the request.

To create a client ID:

  1. In the Google Cloud Platform Console, go to the Credentials page.

    Go to the Credentials page

  2. From the projects list, select the project that you created for the sample API.

  3. Click the Create credentials button, and then select OAuth client ID. If this is your first time creating a client ID in this project, use the sub-steps to set a product name on the consent screen; otherwise, skip to the next step.

    1. Click the Configure consent screen button.
    2. Enter a name in the Application name field.
    3. Click Save.
  4. Under Application type, click Web application.

  5. In the Authorized JavaScript origins field, enter the following:

    http://localhost:8080
    
  6. Click Create.

  7. Copy your client ID. Your complete client ID is similar to the following, but it is unique to the web application in your project.

    271473851874-mtll5dk2vultovbtilt31hakqbinpuvd.apps.googleusercontent.com

For more information about creating client IDs, see Setting up OAuth 2.0.

Configuring the backend code and redeploying

For Cloud Endpoints Frameworks to authenticate the request sent from the JavaScript application, you have to add the client ID you just created to the sample code and redeploy an updated OpenAPI document and the application's backend code.

The following procedure assumes that you have already deployed the sample API from Getting started with Endpoints Frameworks for Java. Make sure that you get a successful response when you send a request to the API as described in Sending a request to the API before starting the following procedure.

To configure the backend code and redeploy:

  1. In the directory where you cloned the java-docs-samples repository, change to the directory that contains the Java sample:

    cd YOUR_WORKING_DIRECTORY/java-docs-samples/appengine-java8/endpoints-v2-backend
    
  2. Open the src/main/java/com/example/echo/Echo.java file in a text editor.

  3. In the @ApiMethod annotation for the getUserEmail method, replace YOUR_OAUTH_CLIENT_ID in both the audiences and clientIds attributes with the client ID that you created.

    @ApiMethod(
        httpMethod = ApiMethod.HttpMethod.GET,
        authenticators = {EspAuthenticator.class},
        audiences = {"YOUR_OAUTH_CLIENT_ID"},
        clientIds = {"YOUR_OAUTH_CLIENT_ID"}
    )
    public Email getUserEmail(User user) throws UnauthorizedException {
      if (user == null) {
        throw new UnauthorizedException("Invalid credentials");
      }
    
      Email response = new Email();
      response.setEmail(user.getEmail());
      return response;
    }
  4. Save the Echo.java file.

  5. Clean your project and then build your API:

    Maven

    mvn clean package

    Gradle

          gradle clean
          gradle build
  6. Regenerate the OpenAPI document, openapi.json, so that it contains the client ID.

    Maven

    mvn endpoints-framework:openApiDocs

    Gradle

    gradle endpointsOpenApiDocs
  7. Make sure that the Cloud SDK (gcloud) is authorized to access your data and services on GCP:

    gcloud auth login
    
  8. Set the default project for the gcloud command-line tool. Replace YOUR_PROJECT_ID with the project ID that you created for the sample API:

    gcloud config set project YOUR_PROJECT_ID
    
  9. Deploy the updated OpenAPI document:

    gcloud endpoints services deploy target/openapi-docs/openapi.json
    
  10. Wait for the command to finish and then redeploy your application:

    Maven

    mvn appengine:deploy

    Gradle

    gradle appengineDeploy

Configuring the JavaScript code

To configure the JavaScript code:

  1. In the web-docs-samples/endpoints-frameworks directory, open the main.js file in a text editor.
  2. In the initGoogleAuth function, replace YOUR_CLIENT_ID with the client ID that you created.

    function initGoogleAuth (clientId = 'YOUR_CLIENT_ID') {
      gapi.auth2.init({
        client_id: clientId,
        scope: 'https://www.googleapis.com/auth/userinfo.email'
      }).then(() => {
        document.getElementById('sign-in-btn').disabled = false;
      }).catch(err => {
        console.log(err);
      });
    }
  3. In the sendSampleRequest function, replace YOUR_PROJECT_ID with the project ID that you created for the sample API.

    function sendSampleRequest (projectId = 'YOUR_PROJECT_ID') {
      var user = gapi.auth2.getAuthInstance().currentUser.get();
      var idToken = user.getAuthResponse().id_token;
      var endpoint = `https://${projectId}.appspot.com/_ah/api/echo/v1/email`;
      var xhr = new XMLHttpRequest();
      xhr.open('GET', endpoint + '?access_token=' + encodeURIComponent(idToken));
      xhr.onreadystatechange = function () {
        if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
          window.alert(xhr.responseText);
        }
      };
      xhr.send();
    }

Sending an authenticated request

  1. In the directory where you cloned the web-docs-samples repository, change to the directory that contains the JavaScript sample:

    cd YOUR_WORKING_DIRECTORY/web-docs-samples/endpoints-frameworks
    
  2. Start your web server to serve index.html on port 8080. The following example uses Python 2.7's SimpleHTTPServer:

    python -m SimpleHTTPServer 8080
    
  3. In your browser, enter localhost:8080.

    The JavaScript application displays two buttons.

    Sign In

  4. Click Sign In. The Sign in with Google page appears.

  5. After you've signed in, click the Send sample request button. The first time you send a request, you might experience a delay of about 20 seconds as App Engine starts up. Endpoints Frameworks intercepts the requests and uses the client ID that you configured in the backend code to authenticate the request. If the authentication is successful:

    1. Endpoints Frameworks passes the request to the sample backend running on App Engine.

    2. In the backend code, the getUserEmail method returns the email address of the user account that you used when you signed in.

    3. The JavaScript client displays a dialog box with the email address.

Overview of the JavaScript client

The JavaScript client uses Google Sign-In, which manages the OAuth 2.0 flow. This section provides a brief overview of the JavaScript client code.

Auth set up

  1. Load the Google APIs Platform Library to create the gapi object:

      <script src="https://apis.google.com/js/platform.js?onload=loadAuthClient" async defer></script>
    </head>
  2. After the Google APIs Platform Library loads, load the auth2 library:

    function loadAuthClient () {
      gapi.load('auth2', initGoogleAuth);
    }
  3. Initialize the GoogleAuth object:

    function initGoogleAuth (clientId = 'YOUR_CLIENT_ID') {
      gapi.auth2.init({
        client_id: clientId,
        scope: 'https://www.googleapis.com/auth/userinfo.email'
      }).then(() => {
        document.getElementById('sign-in-btn').disabled = false;
      }).catch(err => {
        console.log(err);
      });
    }

When you initialize the GoogleAuth object, you configure the object with your OAuth 2.0 client ID and any additional options you want to specify. Typically, you specify the access scope. Scopes enable your application to only request access to the resources that it needs while also enabling users to control the amount of access that they grant to your application. Before you start implementing OAuth 2.0 authorization, we recommend that you identify the scopes that your application needs permission to access. This example requests access to the https://www.googleapis.com/auth/userinfo.email scope, which grants access to view the user's email address.

Sign in

After you've initialized the GoogleAuth object, you can prompt the user to sign in by calling the signIn function of the GoogleAuth object:

function signIn () {
  gapi.auth2.getAuthInstance().signIn().then(() => {
    document.getElementById('sign-in-btn').hidden = true;
    document.getElementById('sign-out-btn').hidden = false;
    document.getElementById('send-request-btn').disabled = false;
  }).catch(err => {
    console.log(err);
  });
}

Make a request with the ID token

When the user finishes signing in, send a request with an Authorization header with the user's ID token:

function sendSampleRequest (projectId = 'YOUR_PROJECT_ID') {
  var user = gapi.auth2.getAuthInstance().currentUser.get();
  var idToken = user.getAuthResponse().id_token;
  var endpoint = `https://${projectId}.appspot.com/_ah/api/echo/v1/email`;
  var xhr = new XMLHttpRequest();
  xhr.open('GET', endpoint + '?access_token=' + encodeURIComponent(idToken));
  xhr.onreadystatechange = function () {
    if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
      window.alert(xhr.responseText);
    }
  };
  xhr.send();
}

What's next

Was this page helpful? Let us know how we did:

Send feedback about...

Cloud Endpoints Frameworks for App Engine
Need help? Visit our support page.