API Security with OIDC by using Apache APISIX and Microsoft Azure AD
Tags: api, security, plugin, azure
Published: 2022-06-08 18:15:26

## Introduction

This blog post will cover how to utilize open-source project [Apache APISIX](https://apisix.apache.org/) and [OpenID Connect (OIDC) Plugin](https://apisix.apache.org/docs/apisix/plugins/openid-connect) for [Azure Active Directory (Azure AD)](https://azure.microsoft.com/en-us/services/active-directory/) as the [identity provider](https://docs.microsoft.com/en-us/azure/active-directory/external-identities/external-identities-overview). It contains conceptual introductions of Apache APISIX and its OIDC Plugin. It also provides detailed step-by-step instructions on setting up APISIX OpenID Connect Plugin to secure your API.


## Apache APISIX Overview

[Apache APISIX](https://apisix.apache.org/) is a lightweight open-source API gateway that sits in front of your upstream services. Easy to configure and quick to deploy, APISIX API Gateway serves as a central point for routing all incoming requests to their intended destinations, whether that be an upstream API server, a third-party service, a database, or even a serverless. The API gateway is further extended with countless built-in plugins to handle [authentication](https://apisix.apache.org/plugins#authentication), [authorization](https://apisix.apache.org/plugins#security), [traffic control](https://apisix.apache.org/plugins#Traffic%20Control), and [security](https://apisix.apache.org/plugins#security). As we are going to use one of them APISIX OpenID Connect Plugin.

## OpenID Connect Plugin Overview

[OpenID Connect (OIDC)](https://openid.net/connect/) is a centralized identity authentication mode. The benefit of using OpenID Connect is that users only need to register and log in with one OpenID Connect identity provider’s website like Azure AD and use one account’s password information to access different applications. OpenID Connect Plug-in for Apache APISIX supports OIDC to simplify the development process, and improve security at the API Gateway level. It alone interacts with the identity provider and can intercept unauthenticated requests in time to back-end applications.

## Centralized Authentication Flow with IDP

When we use the OIDC plugin together with any identity provider (In addition to Azure AD, there is a variety of IDP providers such as [Okta](https://www.okta.com/), and [AWS Cognito](https://aws.amazon.com/cognito/)), commonly the authentication flow is divided into 3 stages, **sign-in**, **access**, and **session** flow:

### Sign-in flow

1. The client service requests access to the APSIX API gateway. 
2. APISIX initiates an authentication by redirecting the client request to the Identity Provider, in our case it is Azure AD.
3. The user logs in and authenticates on the Azure AD.
4. The Azure AD IDP returns to APISIX API Gateway with the Authorization Code and redirects the client request back to APISIX.

![Sign-in flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/afcoxszvozms81eq60w3.jpg) 
 
As you can see from the diagram, APISIX does not allow unauthenticated requests to pass to upstream services (backend services).

### Access flow

1. APISIX requests the identity provider with the Authorization Code extracted from the request parameters in the previous flow.
2. The IDP sends an answer message to APISIX with the Access Token.
3. After validating the token, finally, APISIX sends user info to upstream services. Inside services only accept connections from API Gateway.
 
![access flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cqypu8qjt0rpiba5l2ca.jpg)
 
### Session flow

Up to now, authentication has already happened, and in the later stages, the client application can request directly APISIX without duplicative verification with OKTA by using Access Token until the request session expires. However, upstream services should be able to handle custom headers with user info. 
 
![Session flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0qoynteokd2c3ddrop18.jpg)
 

## Prerequisites

Before making use of OIDC plugin with Azure AD, we must have few things ready.

### Install Apache APISIX

There are many ways to install and run APISIX. See [Installation guide](https://apisix.apache.org/docs/apisix/how-to-build).
For this demo, I used simply the build option with docker-compose.

### Azure AD Configuration

1. **Create Azure account** that has an active subscription. [Create an account for free](https://azure.microsoft.com/en-gb/free/?WT.mc_id=A261C142F).

![Create Azure free account](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xleamnhxmwpc5jwz98vs.png)
 
2. **Register an application** with the Microsoft identity platform. See [Register an application](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app#register-an-application).

![Register an application](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8mz66k8zedfm55g9gep.png)
 
3. **Add a client secret** for your application. See [how to add new client secret instruction](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app#add-a-client-secret) on Azure portal. Copy generated client cert and save somewhere so that you can use it later for OIDC plugin configuration. This secret value is never displayed again after you leave this page.

![Add a client secret](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ra4ee13itbi40tnpvjlr.png)
 
4. **Update Manifest** on your application view, update accessTokenAcceptedVersion to 2 (default is null). See [Configure APP Manifest](https://docs.microsoft.com/en-us/azure/active-directory/develop/reference-app-manifest#configure-the-app-manifest).

![Update Manifest](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hglfnvwj0nyb6d513oil.png)
 
5. **Add a redirect URI** to your application. It will be the URI you specify later on OIDC plugin property when configuring your route. You can add one via the Authentication section of the app settings. See the following [Add a redirect URI](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app#add-a-redirect-uri). For example, it can be like `https://httpbin.org/get` or `https://127.0.0.1/get`. Just make sure that it starts with HTTPS and matches _redirect_uri_ attribute of _openid-connect_ plugin.

![Add a redirect URI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ivob27li4yj21t4we2jx.png)
 
---

## OIDC Plugin Configuration

Once you have all set, we can configure the OIDC plugin for a route. We use curl command to create new route and enable the OIDC plugin for it. You can customize below example route configuration with your specific values:

``` bash
curl  -XPOST 127.0.0.1:9080/apisix/admin/routes -H "X-Api-Key: edd1c9f034335f136f87ad84b625c8f1" -d 
'{
    "uri":"/*",
    "plugins":{
        "openid-connect":{
            "client_id":"<YOUR_CLIENT_ID>",
            "client_secret":"<YOUR_CLIENT_SECRET>",
            "discovery":"https://login.microsoftonline.com/YOUR_TENANT_ID/v2.0/.well-known/openid-configuration",
            "scope":"YOUR_CLIENT_ID/.default",
            "bearer_only":false,
            "redirect_uri":"https://httpbin.org/get"
        }
    },
    "upstream":{
        "type":"roundrobin",
        "nodes":{
            "httpbin.org:80":1
        }
    }
}'
```

The above code example creates a route through the Apache APISIX Admin API, setting the route upstream targets to [httpbin.org](http://httpbin.org/). It is a simple mock backend service for receiving and responding to requests. Let's go through some properties of `openid-connect` plugin:

| Field  | Description|
| ------ | ------ |
| client_id | Client id of app registered on Azure earlier. Define YOUR_CLIENT_ID with the client ID shown on the app **Overview** page. |
| client_secret | Client secret is the secret you created for the app. The app uses to prove its identity when requesting a token from Azure AD. Replace YOUR_CLIENT_SECRET with the secret you created earlier in the **Certificates & secrets** section. |
| scope | Scope for your app api |
| discovery| Service discovery endpoint for identity providers. The discovery field value, you can retrieve by clicking the **Endpoints** button on your app registration’s **Overview** page. |
| redirect_uri | The URI that the Azure AD IDP redirects back to, defaulting to the request address after successful authentication. It should be the URI you specified earlier when configuring your app. |

> In this example, the plugin enforces that the access token object be set in the request Authorization header when you try to access the route.

For other configuration items, please refer to [Apache APISIX OpenID Connect Plugin](https://apisix.apache.org/docs/apisix/plugins/openid-connect/).

## Testing OIDC Plugin

Up to now, we introduced new route with OIDC plugin enabled and defined plugin configuration for [Azure AD identity provider](https://docs.microsoft.com/en-us/azure/architecture/multitenant-identity/authenticate). Now you can follow these instructions to test authentication flows for two different use-cases. One is service to service communication where the requester can obtain a token from Azure AD itself in the client code implementation and manage the token to access upstream service. Another is where the client or the requester is a human interacting through a web browser.

### Validate service-to-service flow

#### Step 1: Collect a token from Azure AD

```bash
curl -X POST https://login.microsoftonline.com/<your_tenant_id>/oauth2/v2.0/token \
--data scope="<your_client_id>/.default" \
--data grant_type="client_credentials" \
--data client_id="<your_client_id>" \
--data client_secret="<your_client_secret>"  

```

#### Step 2: Request the endpoint with the token 

You will use token obtained in the above step and set it to an authorization header of the request:

```bash
curl -i -X GET http://127.0.0.1:9080/get -H "Host: httpbin.org" -H "Authorization: <token_from_azure_ad>"
```

### Validate sign-in flow

Visit `http://127.0.0.1:9080` in your browser and the page will be redirected to the Azure AD sign-in page as the OpenID Connect plugin is already enabled. 

![Azure AD sign-in page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jhexihhlj882ckximnxm.png)
 
> Azure AD sign-in page can be customized too. See [Add branding to your organization's sign-in page](https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/customize-branding)

You can authenticate with your user credential which is also used for creating your Azure account. After successful authentication, you will be redirected to redirect URI we specified earlier in the route config and app authentication `https://httpbin.org/get`.

## Summary

We discovered yet another advanced usage of APISIX as a centralized authentication and authorization handler. Apache APISIX has 10+ security related plug-ins that can cope with many API security problems. Go to Apache APISIX's [Plugin hub](https://apisix.apache.org/plugins#security) to observe more.


To learn more⤵️

➔ [Download Apache APISIX](https://apisix.apache.org/downloads )

➔ [Install Apache APISIX](https://apisix.apache.org/docs/apisix/how-to-build)

➔ Watch Video Tutorial [Getting Started with Apache APISIX](https://youtu.be/dUOjJkb61so)  

➔ Watch Video Tutorial [Getting Started with Apache APISIX Dashboard](https://youtu.be/-9-HZKK2ccI)
 
➔ Watch Video Tutorial [Centralized Authentication with Apache APISIX Plugins](https://youtu.be/kbELyQIXAsw)

Community⤵️

🙋 [Join the Apache APISIX Community](https://apisix.apache.org/docs/general/community) 
🐦 [Follow us on Twitter](https://twitter.com/ApacheAPISIX)
📝 [Find us on Slack](https://join.slack.com/t/the-asf/shared_invite/zt-vlfbf7ch-HkbNHiU_uDlcH_RvaHv9gQ)
📧 [Mail to us](dev@apisix.apache.org) with your questions