By Léon Rodenburg, Alibaba Cloud MVP.
Serverless applications are awesome. The zero-maintenance and low-cost solutions that you can build with serverless technologies like API Gateway, Function Compute and Table Store scale massively as your product becomes more and more popular. Although you can outsource a lot of the tasks necessary for running your code and storing your data, application security is one of the aspects that you have to manage yourself. Unfortunately, security is hard to get right. Especially when it comes to OAuth 2 flows, it can be extremely complicated to implement the standards correctly. Luckily though, there are a lot of third-party providers that offer you authentication and authorization out of the box. In this article I will show you how you can secure Alibaba Cloud API Gateway using Auth0, one of the more popular authentication providers.
Assuming you have an API Gateway in place with a backend you want to secure, let’s start with setting up your Auth0 account. If you don’t know how to provision an API Gateway with a backend, like a Function Compute function, there are a lot of online sources that can point you in the right direction. You can find a great introductory tutorial here. If you have everything set up, let’s continue.
Configuring Auth0 Account
It is very easy to get started with Auth0. You can register an account here if you don’t have one yet. When you are logged in, go to the APIs tab to create a new API resource for your application. Click the Create API button in the top-right corner and fill in a name and identifier. You can keep the signing algorithm at RS256. Click Create to set up the API. Keep the rest of the settings as-is.
Auth0 uses JSON Web Tokens (JWTs) for authentication and authorization. JWTs are a well-documented standard and used throughout the web. A JWT is nothing more than a simple JSON blob with identity information of the logged in user. It includes a signature that can be verified by the backend API. When a user logs in, the JWT is created and signed by the authentication provider using a JSON Web Key (JWK). As JWKs are asymmetric keys, there is also a corresponding private key. The private key is never shared with anyone, so only the authentication provider can sign tokens using that key. The signed JWT is then sent to the backend API with every request. The backend API verifies the token by checking the signature using the public key. If everything is okay, it knows that nobody tampered with the token and the application can proceed with providing the requested information. It’s okay if the flow seems a bit complicated, it will become clearer once you get to work with it. For now it’s enough to know that a JWK with a private and public key are used to sign JWTs so no one can tamper with them.
Before we can configure API Gateway to verify the tokens we sent it, we need to note down the public key that Auth0 has generated for your account. You can find the public key at the following URL:
YOUR_DOMAIN with the Auth0 domain you created when registering your account. It is either an auth0.com subdomain or, if configured, your own domain. If you browse to the URL, you should get a JSON response in roughly the following format:
Copy your JSON into a text file and store it somewhere you can find it easily for the next step.
Setting up API Gateway Plugin
Although it is not the most well-documented feature of API Gateway, plugins can be used to extend the functionality that API Gateway provides. When you open the Alibaba Cloud console, go to API Gateway and then click Plugin on the left. Make sure to pick the region where your API is also deployed, as you can only apply plugins that were created in the same region.
Click Create Plugin to create a new plugin. Give the plugin a name (like
Auth0) and select the
JWT (OpenID Connect) plugin type. In the Script Configuration tab, you should see an example of the plugin configuration that needs to be done. You can study the comments in the example to learn more about the capabilities of the plugin (although some of it is in Chinese). For now, clear the script and replace it with the following:
In the configuration we specify where the token can be found when a request comes in. In this case, we specify that API Gateway must look in the
Authorization header on every request for the token.
The fields under the
jwk property should look familiar, as these are exactly the public key fields that you copied earlier. So, take out the file you stored and replace the values for the one that apply to you. When you are done, click Create to create the plugin.
Back on the plugin overview, click the Bind API link for the plugin you just created. Select the right group and stage from the dropdowns and click the Add button next to the API that you want to bind. If you can’t find your API, make sure it was published to the Test, Pre or Release stages and that it is in the same region as your plugin. Correct this if necessary and click OK to save the changes.
Your API is now bound to the plugin! In the last step we need to configure the API to expect the
Authorization header as a parameter.
Adding Token Parameter to API
Now click APIs in the left menu to go to the APIs that you want to secure. You will need to repeat these steps for all the APIs that need to be secured. Click the API name and then Edit to start editing the API.
We need to change the Security Certification value to
OpenID Connect. The OpenID Connect field will show up below. Select
Business API here. Then, fill in
Authorization for the Token Parameter Name. The form should reflect the following:
When that is done, click Next.
On the next page, look down to the Input Parameter Definition and click Add to add an input parameter. The Param Name should be
Authorization, the Param Location is
Head and it is a string. Also make sure to check the Required checkbox so people are forced to include it. When your parameter reflects the setting below, click Save to save the API and go back to the dashboard.
Finally, we can deploy the new version of the API that includes the
Authorization parameter. Click Deployand select the right stage to deploy the secured API.
Testing the Setup
Now that everything is configured correctly, we can check to see if the setup has worked. Although we won’t go into a lot of detail on how you can acquire a JWT from a client application with Auth0 (this is explained pretty well in their documentation), there is an easy way for us to get a token quickly. To get it, log into the Auth0 dashboard and go to APIs. Then, click the API you created a few steps before. Below the title, you should see several tabs, one of which is called Test. Click this tab to get a token.
On the Test page, there is an example request and response for getting a token. The response should already be shown with an
access_token and a
token_type. Copy the access token by hand or click the Copy Tokenbutton to copy it. The access token is a Base64 encoded JWT. If you are interested, you could try finding out what is in it using the great online tool jwt.io. For now, keep the page open so you can grab the token in a second.
Now, find the URL of the API you want to hit. This is built up from the URL of the API Group plus the request path of the API. First go to the API Gateway dashboard and click API Groups. Click the group your API was deployed in and copy the Internet Subdomain. This is the base URL of your API.
Next, go to the APIs page and select the specific endpoint you want to hit. Under the Basic Request Definitionyou should see the path. In this case, the path is
To get the final URL, combine the Internet Subdomain and the request path into a single string. Assuming you have configured the
HTTP protocol, the final URL for this example would be
Open a terminal and paste in the following command, replacing
<URL> with the final URL you just combined and
<TOKEN> with the
access_token property value you grabbed earlier:
curl -v -H Authorization:"<TOKEN>" <URL>
If everything worked, you should get the expected output from your backend! Now remove the
Authorization header and try again:
curl -v <URL>
You should get a 400 Bad Request response with an
X-Ca-Error-Message header that says
Missing JWT Parameters. As an exercise, you can try what happens if you put in an invalid token (modifying the Base64 encoded string by changing a few digits) or using an invalid token (for example, one that has expired).
And we’re done! As a small recap, let’s reiterate on what we’ve done. We have set up an Auth0 account and configured an API in the Auth0 dashboard. Then we used an API Gateway plugin that can verify JWT tokens and bound it to our API. The plugin configuration specifies where API Gateway can find the token parameter, so we made sure our API expects an
Authorization header. Finally, we tested the setup by calling the API with a token provided by the Auth0 dashboard. In a real application, the frontend application would call Auth0 for a token and provide that to the backend.
A next step would be to update your backend to also parse the JWT. One of the more important fields in the JWT is the
sub (subject) field, that contains the username of the user that has logged in through Auth0. You could use that to only return the data from that specific user in your API responses. There are many libraries out there that will parse JWTs for you and verify their signature. Using the configuration discussed in this article, you can build a pretty robust API on Alibaba Cloud while all the hard parts of security are already done for you!