Authenticating Users with Cloud Functions, API Gateway, and App ID

By: Matt Hamann, David Green, and Beery Holstein

Build an IBM Cloud Function API and use IBM Cloud App ID to protect it with the IBM Cloud API Gateway

Over the past decade, running software on a network has shifted from monolithic applications deployed on gigantic servers to microservices packaged within containers to individual functions deployed on a serverless platform like IBM Cloud Functions.

This shift in deployment models has also significantly changed how middleware needs to be configured and deployed in support of these application components. With the growing adoption of serverless, the deployment of middleware has shifted from global handlers within application code to placing middleware components in the network itself.

Authentication and authorization are key components for any web app, and APIs built as cloud functions are no exception. This article will show you how to build an IBM Cloud Function API and then use IBM Cloud App ID to protect the function with the IBM Cloud API Gateway—no code change required. Best of all, you can get started for free!

Step 1: Configure App ID

Let’s begin by creating and configuring an App ID service instance.

  1. Navigate to the IBM Cloud catalog.

  2. Search for App ID using the catalog search bar, or select the Security and Identity category on the left.

  3. Click on the App ID catalog entry:
    App ID

  4. Select the desired deployment region (this tutorial requires either Dallas, London, or Frankfurt).

  5. Click Create at the bottom of the screen. The App ID dashboard will be displayed:
    Create

Now that App ID is provisioned, it’s time to configure an OAuth2 client.

  1. Navigate to the Application section from the left-hand navigation bar:
    Application

  2. Click the Add application button to launch the application creation dialog:
    Add application

  3. Enter an application name (this name can be anything that you want):
    Enter an application name

  4. Click Save.

  5. An entry for the application should now be visible in the Applications table. Select the View credentialsdropdown to expose the credentials for your application. Record these, as we’ll use them in Step 4:
    View credentials

Step 2: Create a cloud function

If you’ve already built an IBM Cloud Function, feel free to skip to Step 3. Now that our App ID service is ready, let’s create the function that we want to protect.

  1. Open the IBM Cloud Functions dashboard in a new tab.

  2. Click Start creating from the getting started page.

  3. Select Create action:
    Create action

  4. Give your action a name (e.g., get-customers) and select Node.js 10 from the Runtime field, then click Create at the bottom of the page:
    Node.js 10

  5. The function editor will open, containing the “Hello world” sample code. Delete the boilerplate and replace it with the following code:

    function main(params) {
        var customerData = [{
            "id": 3468450917,
            "name": "John Doe",
            "email": "Jdoe@fake.com",
            "registered": "1-25-19",
            "company": "IBM"
        },
        {
            "id": 58354961,
            "name": "Jane Smith",
            "email": "Jsmith@fake.com",
            "registered": "1-25-19",
            "company": "IBM"
        }]
        
        return {"customerData" : customerData}
    }
  6. Click Save. The editor will look something like the following:
    Save

Let’s test the action before proceeding to make sure it works as intended.

Click the Invoke button near the upper-right. The resulting output should look similar to this:

Invoke

If everything looks good, proceed to Step 3.

Step 3: Expose your function as an API

It’s time to connect everything together with an API. We can accomplish this within the Cloud Functions dashboard.

  1. Select the APIs option from the Functions left-hand navigation, or use this direct link.

  2. If this is the first time you’re creating a Cloud Functions API, a brief welcome page will appear. Click the Create a Cloud Functions API button:
    Create a Cloud Functions API

We can accept many of the defaults, but let’s configure a few options within our new API.

  1. Enter an API name (e.g., “Customer management API”).

  2. Enter a more human-friendly base path (e.g., “/crm”). Next, we need to attach our function to an operation.

  3. Click the Create operation button. The operation configuration dialog will appear.

  4. Provide a path for the operation (e.g., “/customers”).

  5. Ensure the function that we created in Step 1 is selected in the dropdown. The dialog should now look like this:
    Step 1

  6. Click Create. A row representing the operation should appear in the Operations table:
    Operations table

Finally, let’s secure our API using the App ID instance created previously.

  1. Scroll down the page and find the section for OAuth user authentication.

  2. Click the toggle switch labeled Require users to authenticate via OAuth social login.

  3. Select IBM Cloud App ID as the provider.

  4. In the App ID service dropdown, select the instance created in Step 1. The resulting configuration should look something like this:
    App ID service

  5. Click the Save & expose button at the bottom of the page. The API summary panel should appear. The base URL of the API is displayed near the top:
    Save & expose

If you attempt to invoke the API now, it should return a 401 Unauthorized response, since you didn’t provide a valid access token.

$ curl -X GET https://77ea58bd.us-south.apiconnect.appdomain.cloud/crm/customers
{"status":401,"message":"Error: No Authorization header provided"}
$ curl -X GET https://77ea58bd.us-south.apiconnect.appdomain.cloud/crm/customers \
      -H 'Authorization: invalid bearer token'
{"status":401,"message":"Error: AppId key signature verification failed"}



Step 4: Get an access token from App ID

Now it’s time to use the App ID application credentials we saved back in Step 1.

We need to generate an access token to authenticate ourselves to the API gateway, which should then allow us to invoke the cloud function. An access token is typically a short-lived credential that is generated from a set of known credentials (e.g., username and password). By using an access token, users can protect their actual credentials from third parties while still being trusted by a remote system. If you want to learn more about how access tokens work, take a look at the App ID documentation.

Generate an access token

  1. From the App ID application credentials, replace the corresponding values in the following `curl` command, then execute it.

    $ curl -X POST <oAuthServerUrl>/token \
           -H "Authorization: Basic $(echo -n <clientId>:<secret> | base64)" \
           -H 'Content-Type: application/x-www-form-urlencoded' \
           -d grant_type=client_credentials
  2. The result from the curl command should include an access token that looks something like this:

    {"access_token":"eyJhbGci0iJSUzI1NiIsInR5...","expires_in":3600,"token_type":"Bearer"}

Copy the token to your clipboard for use in Step 5.

Step 5: Invoke the API

Now that we have a valid access token, we can use it to invoke our customer list API, which is backed by a cloud function.

  1. Copy the following curl command into your terminal.

  2. Replace <access_token> with the token copied in Step 4.

    $ curl -X GET https://77ea58bd.us-south.apiconnect.appdomain.cloud/crm/customers \
          -H 'Authorization: Bearer <access_token>'
  3. Execute the curl.

The output from the invocation should be a JSON formatted list of customers from our cloud function:

{
  "customerData": [
    {
      "id": 3468450917,
      "name": "John Doe",
      "email": "Jdoe@fake.com",
      "registered": "1-25-19",
      "company": "IBM"
    },
    {
      "id": 58354961,
      "name": "Jane Smith",
      "email": "Jsmith@fake.com",
      "registered": "1-25-19",
      "company": "IBM"
    }
  ]
}

Now, only users with a valid access token from your unique instance of App ID can invoke your application logic. To prove the security of the network flow, try some of these scenarios:

  • If you change even one character of the access token, what happens?

  • If you create a new App ID service instance and use a token from it, what’s the result?

  • Wait for the original token to expire, then try invoking the API again. Does it work?

Conclusion

In this article, you leveraged three IBM Cloud services to build a modern web API powered by Cloud Functions, App ID, and the API gateway. Using this approach with your next project could save you time and money. Since cloud functions only run when invoked, they cost nothing when idle and scale infinitely. App ID takes the pain out of setting up user authentication, whether using an enterprise identity provider (such as Active Directory or Ping Identity) or connecting to popular social authentication services provided by Google, Facebook, and others. The API gateway ties everything together with a highly-performant and resilient proxy capable of protecting backend resources from unauthorized access.

As always, we’d love to hear your feedback and questions! Get help for technical questions at Stack Overflowusing the following tags:

  • App ID: ibm-appid

  • Cloud Functions: ibm-cloud-functions

  • API Gateway: ibm-cloud & api-management

For defect or support needs, use the Support section in the IBM Cloud menu.

To get started with any of the IBM Cloud services mentioned here, check them out in the IBM Cloud Catalog.

Be the first to hear about news, product updates, and innovation from IBM Cloud