Connecting an Apigee Edge API Proxy with Auth0 Platform

Written by shahilyas | Published 2021/01/08
Tech Story Tags: api | apigee | api-management | backend | authentication | security | auth0 | rest-api

TLDRvia the TL;DR App

Apigee Edge, the API management platform, already has a well-defined OAuth2 policy that supports various OAuth2 grant types. In addition to that, Apigee also supports integration with an external OAuth system and relying on the Authentication flow of the external system to provide security for the APIs proxied via Edge. There are 2 ways to execute:
  1. Using an external OAuth system like Auth0 just for User Authentication by creating and persisting an Apigee Access token within Apigee and using that for authorization using the OAuth v2 policies
  2. Using an external OAuth system (Auth0) for authentication and using the Access token created by the external system and persisting and recognizing that token within Edge.
In this post, we will explore the second option. This is because we may have users stored in an external OAuth system like Auth0 and it delegates access tokens on successful authentication of the users. Since on Apigee, we also use access tokens to secure our APIs, it will be beneficial if we can use the same access tokens that were generated by auth0 and verified by Apigee. This reduces the work for Apigee to generate its own tokens and also ensures that the token is generated for a legitimate user.

What is Apigee Edge?

Apigee Edge is an API management platform that helps you expose your backend services (APIs) to your client applications in a secure and well-defined manner. Apigee creates an API proxy that acts as a facade for the client applications which want to access your APIs. Apigee lets your backend services focus only on the core business logic and frees them from the concerns of access control, traffic rate-limiting, data mediation, and so on.

What is Auth0?

Auth0 is an identity-as-a-service platform that provides identity-related services like Authentication (AuthN) and Authorization (AuthZ). It is a developer-friendly identity management solution, providing an easy path for developers to integrate their applications by providing SDKs for a wide range of programming languages and frameworks. It also provides integration with various popular social identity providers like Facebook, Google, Linked In, etc, and also provides integration with different enterprise identity management solutions like Azure Active Directory, LDAP, etc.
Flow:

Let’s develop the solution:

Step 1: Setup an Auth0 application
Auth0 application is a way to integrate different types of apps with Auth0. It provides us an app ID that is required when integrating a particular app with Auth0 or when requesting an access token for a user. We can think of an Auth0 app as a link that connects our apps with Auth0 and through it we can use different services offered by Auth0. To create the application we need to do the following steps:
  1. In the Auth0 dashboard, click on Create Application.
  2. Choose the application type as Single page application and click on Create. This should create the Auth0 application and display the application settings page.
Step 2: Setup an Auth0 API
Auth0 API lets us define the API URL of our backend application that we want to secure with Auth0 access tokens and in our case, we want to secure an Apigee API proxy, so we will mention its URL. When connecting with Auth0 from an app, we can specify an audience parameter with API proxy URL as its value. This tells Auth0 that this app wants to have an access token specific to this particular API or API proxy. Later on, when Apigee validates this access token, it will check for the audience parameter.
Step 3: Create a user in Auth0
To authenticate a user, we need to create a user in Auth0 which we can later use when authenticating with Auth0. Note that the user needs to be present in the Auth0 database or if it is present in an external database, then it should be imported to Auth0 database first. 
We can create users directly in the users section in the Auth0 dashboard.  To create a user, we need to mention the user email, password, and connection type. The connection type in our case is “Username-Password-Authentication” which means we can use username and password when authenticating with Auth0. It also means that the user will be created in the default Auth0 database.
Step 4: Add policies to API proxy to validate Auth0 access tokens
Our API proxy should be able to validate/verify the access token that is present in the API request. In order to do so, we can use Apigee’s VerifyJWT policy to verify the access token from the Auth0 as they are JWT based access tokens. When configuring the Verify JWT policy, we need to mention the following key parameters:
  1. Public key: This is the public key of the Auth0 tenant and is used to verify the signature on the JWT access token.
  2. Audience (aud): This is the URL that we mentioned in the second step when creating an API in Auth0. Apigee will make sure that this URL matches the URL of the API proxy. This will be present as a standard “aud” claim in the JWT access token.
  3. Issuer (iss): This is the domain name of our Auth0 tenant that issued the access token. Apigee will make sure it matches the issuer (iss) claim in the access token.
The final policy configuration should look like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<VerifyJWT async="false" continueOnError="false" enabled="true" name="VJ-VerifyAuth0AccessToken">
    <DisplayName>VJ-VerifyAuth0AccessToken</DisplayName>
    <Algorithm>RS256</Algorithm>
    <Type>Signed</Type>
    <PublicKey>
        <JWKS uri="https://{auth0_domain}/.well-known/jwks.json"/>
    </PublicKey>
    <Issuer>https://{auth0_domain}/</Issuer>
    <Audience>https://{apigee_domain}/test-api</Audience>
</VerifyJWT>

Testing our solution

Now that we have set up all the things that we require, it’s time to test our implementation. To test our setup, we will use  Postman, the API testing tool. It can make HTTP requests to our API proxy and we can also attach an access token with the request.
Generate the access token
To authenticate a user with Auth0 and to get an access token from Auth0, we will use the Auth0 token endpoint with the OAuthV2 password grant type. In the API request to Auth0 token endpoint, we need to mention the following information:
  • URL: https://{auth0-tenant-url}/oauth/token
  • Headers: Content-type: application/x-www-urlencoded
  • Form params:
    grant_type: “password”
    client_id: Auth0 app ID
    audience: “https://{apigee_domain}/test-api
    scope: it is used to ask for more information about the user that will be available in the access token.

    Openid: (required; to indicate that the application intends to use OIDC to verify the user's identity)

    Profile: optional; so you can personalize the email with the user's name

    Email: optional; so you know where to send the welcome email

    Additionally if our API requires some other scope for retrieving resources, then we can mention those as well.
  • username:
  • Password:
Request (CURL)
curl --location --request POST 'https://{apigee_domain}/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=mCKhEC7x5a0E323xxxxxxxxxxxx' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'scope=openid email profile' \
--data-urlencode 'audience=https://{apigee_domain}/test-api' \
--data-urlencode '[email protected]' \
--data-urlencode 'password=test@123'
Response
{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR..........",
    "id_token": "eyJhbGciOiJSUzI1NiI...........",
    "scope": "openid email profile",
    "expires_in": 86400,
    "token_type": "Bearer"
}
API request with an invalid access token:
When we make an API request to our API proxy endpoint without an access token, it should respond with a 401 unauthorized error. In the below image, our API proxy responded with an error response because our Verify JWT policy was not able to find the access token. Hence rejected the API request:
Request:
curl --location --request GET 'https://{apigee_domain}/test-api' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cC.......'
Response:
{
    "fault": {
        "faultstring": "Invalid token: policy(VJ-VerifyAuth0AccessToken)",
        "detail": {
            "errorcode": "steps.jwt.InvalidToken"
        }
    }
}
API request with an access token:
Now, we will make an API request to our Apigee endpoint with an access token. The access token should be added as an “Authorization” request header as:
  • Authorization: Bearer <access_token>
Once we add the access token with the request, we can click on send, and in the response, we should be able to get a 200 success response from the API proxy with the response data. At this moment, we can conclude that our JWT policy has successfully validated the access token.
Request:
curl --location --request GET 'https://mohdilyas-eval-test.apigee.net/test-api' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImNmUjJ0TmVsalNFSFAySHVzWjhQMiJ9.eyJpc3MiOiJodHRwczovL2lseWFzLWF1d........'
Response:
Hello, Guest!
Conclusion
When developing the solution, testing forms an equally important aspect as it validates the quality of execution. A similar approach can be used with other identity providers like Amazon Cognito, OKTA, etc. It could be possible that our users are stored or managed by a different identity provider than Auth0. As long as that provider is capable of providing JWT access tokens, this solution can be used there as well. Besides verifying the token, Apigee can decode it as well, which means we can have access to all the claims of the token as “flow variables” and those can be used to implement other use cases within the API proxy.
This approach is suitable for scenarios where we are delegating our authentication and authorization to an external identity management provider. We can integrate this external system with our applications and those apps can use APIGEE to get the data from the backend data services. In case, we are not dependent on an external identity provider, then we can still use APIGEE for generating access tokens and then use them to get the data from the API proxies.

Written by shahilyas | Enthusiastic web developer and API Engineer
Published by HackerNoon on 2021/01/08