AWS Partner Network (APN) Blog

How to Integrate REST APIs with Single-Page Apps and Secure Them Using Auth0: Part 1

Editor’s note: This is the first of a popular two-part series by Aravind Kodandaramaiah. Read Part 2 >>

By Aravind Kodandaramaiah, Solutions Architect at AWS who works closely with Global Systems Integrators (GSIs)

It’s fairly common for customers to host backend REST APIs for their mobile, web, and enterprise applications on Amazon Web Services (AWS). In order to host such REST APIs, you need to think about infrastructure, authorization, monitoring, traffic management, and similar considerations. Amazon API Gateway is a pay as-you-go service that allows you to quickly and easily build and run such REST APIs in a robust and scalable way. Instead of focusing on infrastructure, you focus on your services.

As you run these REST APIs, it is important to secure them by implementing authorization strategies such as JSON Web Token (JWT) verification or OAuth provider callout. In this two-part blog post, I’ll show you how to integrate such REST APIs and secure them by using Auth0. I’ll use a single-page application (SPA) hosted on Amazon Simple Storage Service (Amazon S3) for reference.

Auth0, an APN Technology Partner and AWS Mobile Competency Partner, is an authentication broker that allows you to authenticate and authorize applications and APIs with any identity provider running on any stack, on any device. Auth0 implements proven, common, and popular identity protocols used in consumer-oriented web products (e.g., OAuth, OpenID Connect) and in enterprise deployments (e.g., SAML, WS-Federation, LDAP).

Identity Protocols and Access Tokens

OAuth 2.0 is an authentication protocol that allows users to approve applications to act on their behalf without sharing their password. In order to enable federated access, OAuth 2.0 defines the concept of an access_token. Access tokens are credentials used to access protected resources. An access_token is a string representing an authorization issued to the client. Access tokens can have different formats and structures. JSON Web Token (JWT) is one such access token format.

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained method for securely transmitting information between parties encoded as a JSON object. For example, with JWT, an application could generate a token that has the claim “logged in using Amazon” and provide that to a client. The client could then use that token to prove that the user did log in using Amazon credentials.

Why use JSON Web Tokens?

JSON web Tokens provide a number of benefits compared to traditional cookie based methods.

  • Scalability – Unlike server-based authentication, token-based authentication doesn’t require you to store session state on the server side. This increases the scalability of applications.
  • Reusability – Multiple services or applications could leverage the same token for authorizing.
  • Security – Protection against CSRF, token expiry, and revocation capabilities.

Anatomy of a JSON Web Token

A JSON Web Token consists of three parts: Header, Claims and Signature. The header and payload are Base64 encoded, then concatenated by a period, finally the result is algorithmically signed producing a token in the form of header.claims.signature. The header consists of metadata including the type of token and the hashing algorithm used to sign the token. The payload contains the claims data that the token is encoding. The final result looks like:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJtZXNzYWdlIjoiSldUIFJ1bGVzISIsImlhdCI6MTQ1OTQ0ODExOSwiZXhwIjoxNDU5NDU0NTE5fQ.-yIVBD5b73C75osbmwwshQNRC7frWUYrqaTjTpza2y4

Claims

Tokens issued by Auth0 contain claims, which are statements about a subject (user). For example, the claim can be about a name, identity, key, group, or privilege.

Scopes

Auth0 uses scope values to specify what access privileges are being requested for Access Tokens. Auth0 provides the concept of Rules which allow you to customize the JWT token by adding custom scopes.

Solution Overview

The solution I will illustrate, involves an SPA that lets users log in using Amazon or Google credentials, and access REST APIs over Amazon API Gateway. The solution involves building of two REST APIs that provide access to information about devices and movies. Users who log in with Amazon credentials are allowed to access only the Movies REST API, while users who use Google credentials are allowed to access only the Devices REST API. The SPA will be hosted in Amazon S3. The REST APIs need to authorize these users based on the JWT bearer access token provided by Auth0. In this post, I will show how you can use custom authorizers in Amazon API Gateway to validate bearer access tokens and to implement custom authorization logic. This post uses the concept of implicit grant to secure the REST APIs.

Before proceeding with the solution architecture, let’s understand how implicit grant works. Here’s a representation of the flow.

Image_1_Auth0

  1. The client initiates the flow via the user agent and redirects the user to the authorization server (Auth0). Auth0 exposes an authorization API for this purpose. See AuthO documentation for details about redirecting a user using this API.
  2. Auth0 re-directs the user to a Login screen. The user authenticates (in this example, using either Amazon or Google credentials) with the identity provider.
  3. The authorization server redirects the user to the client with an id_token and access_token in the hash fragment.
  4. The client extracts the tokens from the hash fragment. Refer to the ‘getParameterByName’ function defined in html for details on how tokens are extracted from the hash fragment.
  5. The client uses the access tokens to call the resource server on behalf of the user.

The following architecture diagram shows the implementation of implicit grant flow.

Image_2_Auth0

How does this solution work?

  1. An SPA is deployed as a static website in Amazon S3. See the Amazon S3 documentation for details on hosting static websites on Amazon S3. Users click the login link.
  2. The SPA redirects to Auth0’s authorization API, which presents users with a customized login screen that provides options for Amazon or Google credentials.
  3. After users log in, Auth0 brokers these requests to the appropriate identity providers (Amazon or Google) using the OAuth2 protocol.
  4. Upon successful authentication, Auth0 builds and returns an id_token and an access_token back to the SPA. Before building an access_token, Auth0 executes any rules configured as part of the authentication pipeline and adds scopes to the access_token. The id_token is used to retrieve user profile information to customize the SPA (like displaying the user name or profile picture etc), while the access_token is used to authorize API calls. The process of validating the id_token and customization of SPA is beyond the scope of this post.
  5. The SPA calls the REST APIs exposed over Amazon API Gateway by including the access_token within the Authorization HTTP header.
  6. The API Gateway verifies whether a custom authorizer is registered, and, if so, calls the AWS Lambda function with the access_token.
  7. The custom authorizer Lambda function verifies if the access_token passed is valid and executes custom authorization rules, if any. The actual process of verification will be discussed later in the post.
  8. If the access_token is valid and the request is to be authorized, the custom authorizer Lambda function generates an AWS Identity and Access Management (IAM) Allowpolicy and caches it (configurable). If the authorization token is invalid or has expired, an IAM Deny policy is generated and cached (configurable) to deny access to the API. The IAM policy is returned back to Amazon API Gateway.
  9. The API Gateway evaluates the policy.
  10. The API Gateway allows access to the API if an IAM Allow policy was returned by the custom authorizer Lambda function.
  11. AP Gateway returns status 200/OK to the SPA along with the response payload.
  12. The API Gateway denies access to the API if an IAM Deny policy was returned by the custom authorizer Lambda function and returns 403 Forbidden responses to the SPA.

Solution steps

Configuring Auth0

Before getting into the details of creating and configuring APIs, I’d like to walk you through registering an application, APIs, and rules within Auth0, which you must do first. Here are the steps involved.

    1. Registering the client
      • Sign up with a user name on the Auth0 website. Auth0 provides a free plan which should be sufficient to implement the solution outlined in this blog post.
      • In the Auth0 dashboard, choose +New Client
      • Enter the application name as AWSDemo and choose Single Page Web Applications.
    2. Configuring the client settings
      • Navigate to the application Settings screen and configure the following attributes:
        • Domain represents the domain name and should be in the format domain.auth0.com.
        • Client ID is an auto-generated ID associated with this application. A client application typically specifies the domain name and the client ID when calling an Auth0 API endpoint. This enables Auth0 to know which account and application configuration settings should apply to the call.Image_3_Auth0
        • Allowed Callback URLs should be set to the SPA’s Amazon S3 static website endpoint URL. This is an important security feature, as it allows Auth0 to allow a callback only to the specified URLs after a user authenticates. If the URL is not known at the time of registration, you can update it later.

          Note: The URL you specify might differ from the illustration. Configure it appropriately.

          Note: The URL you specify might differ from the illustration. Configure it appropriately.

      • Navigate to the Connections screen in Auth0 and configure the identity providers supported for user logins. For this post, you will enable Amazon and Google. Image_5_Auth0
    3. Configuring Auth0 Account settings
      • Navigate to Account settings. On the Advanced tab, select Enable APIs Section and OAuth2 as a Service. These features enable us to build the implicit grant flow to secure APIs by generating access_tokens for the API (resource server) configured within Auth0.Image_6_Auth0Image_7_Auth0

      When you choose the Enable APIs Section option, you’ll see a new APIs option in the navigation pane.Image_8_Auth0

    4. Configuring APIs – This section is used to configure the APIs that will be consumed from authorized clients. For this post, define a single API setting which would be applicable to both the Movies and Devices APIs.
      • Navigate to the APIs section and choose +Create API.
      • Provide the API name as StreamingResourceServer and specify a unique identifier (Can be alphanumeric string or a URL). For this post, choose the identifier to be a URL https://StreamingResourceServer.  This URL need not be public facing nor be present and Auth0 does not invoke this URL in anyway.
      • Choose the signing algorithm HS256 (RS256 is also supported, but for this post I choose HS256).

      About Signing Algorithm & Signing Secret

        JWT tokens consists of three parts separated by periods (.):
        • Header
        • Payload
        • Signature

      In order to validate JWT tokens against modifications, JWT tokens have an embedded signature. This signature is created by using one of the signing algorithms along with the signing secret. For example, if you’re using the HMAC SHA256 algorithm, the signature will be created in the following way:

      HMACSHA256(base64UrlEncode(header) + “.” + base64UrlEncode(payload), secret)

      It is important to safeguard the signing secret and not expose it. Only the REST APIs (or API Gateway custom authorizer) and Auth0 need to know about the signing secret.

      • Set the token expiration. This specifies the amount of time before the Auth0 access_token
      • Save these settings. The API settings should resemble the following illustration.Image_9_Auth0
    5. Configuring Rules

Now you’ll create a rule in Auth0. Rules within Auth0 are functions written in javascript that are executed everytime a user authenticated into your application. They let you customize the JWT tokens by adding additional claims such as scopes for authorization, adding profile enrichment data (for example, user information queried from a database/api), enabling multi-factor authentication, etc.

Scopes are used for authorization purposes. For this blog post, you will create a rule that checks whether the user logged in using Amazon credentials. If yes, the rule will add a scope called read:Movies. If a user logged in using Google credentials, a scope called read:Devices is added. This rule gets executed after a user logs into the SPA using either Amazon or Google identity providers and before the access_token gets returned to the SPA from Auth0. Auth0 executes the rule by adding scopes to the access_token and returns it back to the SPA.To create the rule:

      1. Choose Rules in the Auth0 navigation pane, and then choose +Create Rule.
      2. Provide a name for the rule.
      3. Use JavaScript to implement the rule. You will implement the rule as shown below. The code checks to see if the JWT token being requested is for a specific API and then depending on the Identity provider used for authentication, adds a Scope to the access token.
function (user, context, callback) {
  if (context.request.query.audience === 'https://StreamingResourceServer') {
    if (context.connection === 'google-oauth2') {
      context.accessToken.scope = ['read:Devices'];
    }
    if (context.connection === 'amazon') {
      context.accessToken.scope = ['read:Movies'];
    }
}
  callback (null, user, context);
}

Summary and Next Steps

In this post, I’ve demonstrated how you can configure a new client, register a resource server (API), and create rules within the Auth0 portal. In an upcoming post, I’ll walk you through the steps for building REST APIs using API Gateway and securing them by integrating these APIs with Auth0 using a custom authorizer.