Skip to content

Toro Cloud Dev Center


Third-Party Authentication and Authorization

Another way to secure APIs is to use a third-party service such as Amazon Cognito and Auth0 with the help of an API gateway. Consider externalizing the authentication and authorization if you already have an existing auth server or you need to scale it independently. Moreover, most third-party services implement federated identity through various protocols such as OpenID Connect and support integration with social identity providers.

For this tutorial, we will use Amazon Cognito as our auth server and Amazon API Gateway as the entry point of our API. The gateway will be responsible for calling the auth server to check if a user is authorized to call the API.

Prerequisites

Creating and adding a user to Amazon Cognito User Pool

First, we need to create and add a user to our Cognito pool. This user will be used to access our API later on.

  1. Go to Amazon Cognito console and click Manage User Pools > (Your pool name).
  2. Under General Settings, click Users and groups.
  3. Click the Create user button and fill out the form. Be sure to remember the username and password.

Creating Cognito User

Creating an application client

An application client is an entity that is allowed to perform API calls to Cognito. In OAuth 2.0 context, this is the application requesting access to the API on behalf of the Cognito user.

  1. Click App clients under General Settings.
  2. Click Add an app client.
  3. Enter the name of the app client. Configure other settings as necessary.
  4. Click Create app client. Take note of the generated App client ID.
  5. Under App integration > Domain name, specify a domain name. This is to make the Cognito's Hosted UI available which we will use later on.

Adding Cognito App Client

Forwarding requests to the REST API

Now that Cognito is configured, we need to tell Amazon API gateway to forward requests to our API. Amazon API Gateway should be able to access our API for this to work correctly. For example, if your Martini instance is hosted locally, you can expose it to the internet by using a tunneling service such as ngrok. For production environment, it is recommended to only expose your APIs on a private network and make sure they are only accessible through the API gateway.

  1. Go to Amazon API Gateway Console.
  2. Create an HTTP API by clicking the Build button.
  3. Click Add integration and select HTTP.
  4. Paste the URL of the API on the URL endpoint.
  5. Specify an API name, click Review and Create, then Create.
  6. Test the API by invoking the Invoke URL with the path of the API.

Forwarding Requests to Martini

Integrating Amazon Cognito with Amazon API Gateway

Configure the Amazon API Gateway to contact Amazon Cognito for authorization to prevent unauthorized users from calling the API.

  1. Click Authorization under the Develop tab.
  2. Click Manage Authorizers.
  3. Click Create.
  4. Use JWT as the Authorizer type.
  5. Specify a name of the Authorizer.
  6. Enter the issuer URL of your Amazon Cognito instance. The issuer URL of Cognito has the format https://cognito-idp.{region}.amazonaws.com/{userPoolId}. The user pool ID can be retrieved on the General Settings of Amazon Cognito console.
  7. Add the app client ID as an audience and click Create.
  8. Click Attach authorizers to routes.
  9. Click the route and select the authorizer from the list and click Attach authorizer.

To test, hit the API again and you should get a 401: Unauthorized response with body:

1
{"message":"Unauthorized"}

Integrating Amazon API Gateway with Cognito

Authorizing a request

To hit the API successfully, we need to retrieve a valid access token from Cognito and pass this when invoking the API. To do this, we need to initiate an OAuth flow. There are multiple kinds of OAuth flows. The correct flow to use depends on the type of your application client. Auth0 provides a guide on which flow to use. For this tutorial, we will use the code flow and initiate it using OAuth Tools.

Configuring OAuth Tools

  1. In OAuth Tools, create an environment by selecting Environments and clicking New environment.
  2. Input the issuer URL of your Cognito instance then click Discover.
  3. Under the Client tab, click New client. Specify the application client ID and client secret. You can get these details on Cognito's App clients.
  4. Enable the Code Flow then exit the dialog.

OAuth Tools Configuration

Getting an access token

  1. Initiate a code flow by clicking Start Flow and select Code Flow.

  2. Change the environment to the newly created environment.

  3. Allow Cognito to callback to OAuth Tools by adding the OAuth Tools' callback URL to Cognito's App client settings.

  4. Enable Cognito User Pool as an identity provider, allow the Authorization code grant and openid scope then click Save changes. OAuth Tools and Amazon Cognito Integration

  5. In Settings section of OAuth Tools, select the app client, and add openid scope.

  6. Click the Run button then you should be redirected to Cognito's hosted UI.

  7. Input the credentials of the Cognito user that was created earlier then click Sign In. If this is the first time the user has signed in, you may need to change its password. Cognito will then redirect you back to OAuth Tools.

  8. In OAuth Tools, scroll down and click the Redeem code button. Copy the generated access token. OAuth Tools Code Flow

Performing an authorized request

  1. Using an HTTP client such as Martini Desktop's HTTP Client, create a new request and enter the URL of the API.
  2. Under the Authentication tab, set the Type to OAuth 2.0.
  3. Paste the access token and click Send.

If you are using a different HTTP client, add a header with name Authorization and set its value to Bearer {access_token} instead.

Performing an Authorized Request

Retrieving User's Identity

In most cases, you may want to persist the user's identity to the API call. In fact, it is recommended to do so to maintain an audit trail. This audit trail can be useful when tracking API requests.

If your authorization server provides access tokens in signed JWT format, the user identity is usually embedded on the token itself. If the server supports OpenID Connect, it is contained on the ID token instead. This ID token is also sent after doing an OAuth flow. Depending on the auth server and gateway, you can pass either of these to the Authorization bearer header. Martini will then automatically decode the token and makes the user details available through the IdentityMethods.getCurrentUser() function. Since most API gateways automatically include the token to the header, you can immediately use the function to retrieve the user's identity.

If your authorization server provides access tokens in encrypted JWT format, you need to configure a service on the API gateway to decrypt it then pass the decrypted token to the Authorization header when calling the API on Martini. Another option is to configure Martini to get the encrypted token from the header and decrypt it. Decryption is usually done by a client library which can be imported as a JAR.