Suppose a medium-scale enterprise that sells bottled water has a RESTful API (Water API) that can be used to update the amount of water consumed by a registered user. Any registered user can access the API via any client application. It could be an Android app, an iOS app, or even a web application. The company only provides the API—anyone can develop client applications to consume it. All the user data is stored in Microsoft Active Directory. Client applications shouldn’t be able to access the API directly and query to find out information about users. Only registered users can access the API. These users shouldn’t be able to see other users’ information. At the same time, for each update made by a user, the Water API must update the user’s healthcare record maintained at MyHealth.org. The user also has a personal record at MyHealth.org, and it too exposes an API (MyHealth API). The Water API has to call the MyHealth API to update the user record on the user’s behalf. In summary, a mobile application accesses the Water API on behalf of the end user, and then the Water API has to access the MyHealth API on behalf of the end user.
The Water API and the MyHealth API are in two independent domains. This suggests the need for an access-delegation protocol. Again, the catch here is the statement, “the Water API must also update the user’s healthcare record maintained at MyHealth.org.”
The challenge has two solutions.
In the first solution, the end user must get an access token from MyHealth.org for the Water API (the Water API acts as the OAuth client), and then the Water API must store the token internally according to the user’s name. Whenever the user sends an update through a mobile application to the Water API, the app first updates its own record and then finds the MyHealth access token corresponding to the end user and uses it to access the MyHealth API. With this approach, the Water API has the overhead of storing the MyHealth API access token, and it should refresh the access token whenever needed.
The second solution is explained in the above figure. It’s built around the OAuth 2.0 Chain Grant Type profile. The mobile app must carry a valid access token to access the Water API on behalf of the end user. In step 3, the Water API talks to its own authorization server to validate the access token. Then, in step 4, the Water API exchanges the access token it got from the mobile application for a JWT access token. The JWT access token is a special access token that carries some meaningful data, and it’s also signed by the authorization server in the Water API’s domain. The JWT includes the end user’s local identifier as well as its mapping identifier in the MyHealth domain. The end user must permit this action at the Water API domain.
In step 6, the Water API accesses the MyHealth API using the JWT access token. The MyHealth API validates the JWT access token by talking to its own authorization server. It verifies the signature; and, if it’s signed by a trusted entity, the access token is treated as valid. Because the JWT includes the mapping username from the MyHealth domain, it can identify the corresponding local user record.
However, this raises a security concern. If you let users update their profiles in the Water API domain with the mapping MyHealth identifier, they can map it to any user identifier, and this leads to a security hole. To avoid that, the account-mapping step must initiate an OpenID Connect authentication with the MyHealth domain. When the user wants to add their MyHealth account identifier, the Water API domain initiates the OpenID Connect authentication flow and receives the corresponding ID token. Then the account mapping is done with the user identifier in the ID token.
This is one of the ten API security patterns covered in my book Advanced API Security. You can find more details about this from the book.