Apigee & Azure Active directory integration - External Identity provider

Hi all,

Apigee Edge is our strategic platform of choice for API management. However for enterprise identity management we have azure AD as our strategic platform. We are trying to bring these two together

We have a bunch of public facing APIs exposed via Apigee edge (exclusively for our external clients).

The question is how do i use Apigee Edge just as a resource server and use Azure Active Directory for authentication and token issuance. Are there standard integration plug-ins available to do that?

Any help with regards to where to get started would be useful. I have looked at few other posts in the community but it is unclear how to get started and what exactly is required to achieve this integration.

Thanks

N

0 7 8,834
7 REPLIES 7

Apigee Edge can integrate with external identity providers in a number of ways.

You said you want to

use Apigee Edge just as a resource server and use Azure Active Directory for authentication and token issuance.

And here I have a question: what kind of tokens are you talking about? There are things such as "identity tokens", aka id_tokens. These are tokens in JWT format which are issued by Open ID Connect identity providers to identify individuals. Azure Active Directory is one such system that can issue such tokens. Others include Google Signin, Ping Identity, Salesforce.com, and there are more.

These ID tokens are useful for collecting a bunch of metadata about a person, signing it, and then providing it to an "audience" or an app. This is the way that a mobile app might learn of the email address of the user, or the surname, or the group affiliation, or some other metadata that the Identity provider might choose to assert about the subject (person). Because the identity provider signs the JWT with its private key, any party can verify the signature with the public key, and subsequently can rely on or trust the assertions in the token.

Access tokens are different. Access tokens can come in various formats, including JWT or just :opaque: tokens (usually a random string of alphanumeric digits), but the format is not the difference I am talking about here. The key difference is the purpose of the token, what it is used for. The access token is checked by the resource server (often Apigee Edge) in order to verify that the {user, app} tuple that is requesting a resource, should be permitted to request the resource.

So which kind of token do you want Azure AD to issue?

With an access token, the resource server might enforce a simple authorization check - "is this token valid?" - or it may be much more nuanced than that. For example, is this token valid for the given verb+resource path? Does this token have the required scope (READ ACCOUNT, DELETE PROFILE, UPDATE BALANCE, etc)? Is this token within the rate limits prescribed for this API? Apigee Edge is good at all of these sorts of nuanced checks, and in order to perform such checks, Apigee Edge needs to "know" about the token. That means the token must be present in the Apigee Edge store.

Apigee Edge "knowing" about a token is not the same as Apigee Edge issuing the token. Obviously Apigee Edge ⟪knows⟫ about a token when Apigee Edge itself issues the token; and this is the normal case, and is probably the case you see in most of the various examples published here on community or in youtube videos and apijam handson exercises and so on. But it is also possible for Apigee Edge to ingest a token generated by a third-party system, like Azure AD, and then store the token, so that it can be used for all the nuanced checks I described previously. In fact, importing a token is the topic of a community question I answered two weeks ago.

On the other hand it is possible to allow Apigee Edge to check (verify) an ID token and exchange that for a "native" access token. This may be easier and smoother. In this approach, the user employs the app, goes through an OpenID Connect signin, the app receives the id_token from the IDP, and then the app can send the id_token to Apigee Edge; Apigee Edge verifies the token, and then issues a time-limited access token generated by Apigee Edge.

Either importing an access token generated by Azure AD or using Apigee Edge to generate an access token from an inbound id_token, would require the application identifier (aka consumer key, aka client id) to be synchronized across Azure AD and Apigee Edge. Fortunately Apigee Edge allows import of a client id / secret pair via API.

Does this help?

This makes sense. Thanks. We intend to use access tokens (in JWT format) - issued by Azure AD.

In terms of checks, we expect the resource server to be able to

  • validate the token ("is this token valid?")
  • verify the {user:app} tuple (as you put it) that is requesting a resource should be permitted to request the resource.

I understand the need for Apigee to "know" about the token. And we would rather have Apigee "know" the details of a token as opposed to issue the token. There are reasons specific to the domain that we operate which aligns better with use of Azure Active Directory (as a centralised identity server and token dispensary).

Is there an alternative approach to importing client id, key (from Azure AD) to Apigee. If we could, we would prefer to avoid the sync between the two systems (Azure Ad and Apigee for client id and key reconciliation).

There is also a need to expose the our identity and claims management service (which is a wrapper around Azure AD OAuth endpoints) to be exposed via Apigee so that external clients will always ever use APIs exposed via Edge for all things functional and non-functional.

What is unclear at this point is how would we get the exposed client facing identity proxy to internally

  • hook into Azure AD,
  • validate the (client) credentials,
  • issue access_token based on a set on pre-conditions,
  • return it to apigee
  • exchange it for an :opaque: token (while retaining the token in apigee's token store).

Hope this provides the bigger picture. Thanks

I understand the need for Apigee to "know" about the token. And we would rather have Apigee "know" the details of a token as opposed to issue the token.

ok, but let's clarify just a bit. If Apigee Edge validates *opaque* tokens, then Apigee Edge needs to "know" about the token. If Apigee Edge is used to validate a JWT, that's a federated token, and Apigee Edge just needs access to the public key that matches the private key used by Azure.

If Apigee Edge validates the token, there are two possibler outcomes: (1) the token signature is valid. (2) The token signature is not valid. The unhappy path, invalid token, is easy. Apigee Edge just rejects the call. For the happy path, probably you will want Apigee Edge to do some additional validation of the *contentS* of the token. And a great example of this would be; validate the client_id.

The client_id in the token will be inserted there by Azure AD. Apigee Edge can validate that client_id if you have imported that client credential into Apigee Edge.

Is there an alternative approach to importing client id, key (from Azure AD) to Apigee. If we could, we would prefer to avoid the sync between the two systems (Azure Ad and Apigee for client id and key reconciliation).

The import of client credentials, or at least client_id, allows Apigee Edge to validate the client_id in its normal fast-path mechanism. The Edge MP will read from the keystore, and this is a fast operation (cost = ~4ms), and the results are cached, which means subsequent validations cost much less than 1 ms. This approach is time-tested, and allows scale to 10's of 1000's of transactions per second.

If you don't follow this path, the only other alternative I see is to call out to Azure AD, synchronously, to validate the client_id each time. This will be ~100ms for each call, and ... it will not scale like what I just described.

There is also a need to expose the our identity and claims management service (which is a wrapper around Azure AD OAuth endpoints) to be exposed via Apigee...

This sounds like a separate but related issue? Maybe we can resolve one thing at a time.

This is the flow you described as I understand it:

  1. Apigee Edge proxy receives a call
  2. Apigee Edge proxy connects to Azure AD to ask Azure to validate the client credentials
  3. Azure AD responds with an access_token (JWT)
  4. Apigee Edge validates the JWT, and issues an opaque token, storing claims in the token attached to the opaque token
  5. Apigee Edge sends back the opaque token to the original caller

...this flow is possible. It's not even difficult - it will take 5 policies or so. This proposed flow requires the client_id from Azure AD to be known by Apigee Edge, as we discussed previously.

Thanks for your reply. This is really useful.

I like the idea of sharing the public key (with Apigee) that matches the private key used by Azure.

Couple of questions around that

1. Just so i understand, if we do that, then Apigee will be able to validate the signature of the federated token (JWT) that was issued by Azure AD in the first place?

2. Using an "opaque" token (which in my head is a different from the one issued by Azure AD) would mean that Apigee Edge extracts claims from the Azure AD JWT, creates a new token i.e "opaque" token and then pass this token to the client. When the client makes an API request - Apigee would then unpack the opaque token and validate the client_id in its claims against the client_id that it imported from Azure AD.

Do you expect Edge to then pass the original JWT (issued by the Azure AD) to the actual API server or the "opaque" token?

You are right in proposing that we would want Apigee Edge to do additional validations of the "contents" of the token - precisely the validation of client_id, among others.

Now that you mention the latency involved in using Azure AD, i am inclined to go with the option that you propose - import client_ids in Apigee. Would this happen via a custom sync service? Is there any reference i can use to start formulating a view on what this would look like?

Lastly, your summary of steps in the flow is exactly what we require - you mention it will be 5 policies or so - please would you be able to provide more details on what those policies are and how to string them together (if there is an existing post or a wiki page that would be great).

I will take up the identity and claims query in a separate post.

thanks

  1. yes, the public key corresponding to the private key used by Azure AD allows any party to verify signatures generated by Azure AD. In fact every Azure AD tenant has a public wellknown https endpoint at which any party can retrieve all the public keys. They're not secrets!
  2. yes, by the term "opaque token", I imply a string of characters that cannot be decoded. It is in contrast to a decodable token like a JWT.

    Your understanding is correct. The client can send the JWT (of length 512 bytes or more, whatever it is), containing all the claims. Apigee Edge can verify the JWT, and then extract all the claims. Then Apigee Edge can generate a new token, an opaque one. It's just a string of random digits. This random string gets stored in a persistent store in the cloud, and Apigee Edge can attach to it an arbitrary set of claims (We call them attributes, but they are exactly analogous to JWT claims).

    The opaque token cannot be "decoded" by any party. It's just a random string, it contains no other information. But when the client presents this opaque token to apigee edge, Apigee Edge can lookup the token from the persistent store, and retrieve all the previously set attributes (claims), and then take actions based on those claims.

    Think of an opaque token as a lookup key. There can be a large amount of metadata associated to the lookup key, but it is available only to Apigee Edge.

    Yes, one of the things Apigee will do implicitly is validate the client_id associated to the opaque token.


Do you expect Edge to then pass the original JWT (issued by the Azure AD) to the actual API server or the "opaque" token?

Apigee Edge is the gateway. The backend api server need not have either the opaque token nor the JWT. Basically the backend (upstream?) API server is expected to trust Apigee Edge. This may be predicated on a mutual-TLS connection. If appropriate, Apigee Edge can propagate some subset of the claims on the token to the backend system - such as client identifier, group membership identifier, or similar. But this is information that is trusted - it need not be validated by the backend server.

If the backend server needs to validate a token (either opaque or JWT) then what is the point of using Apigee Edge?

i am inclined to go with the option that you propose - import client_ids in Apigee. Would this happen via a custom sync service?

Yes. You'd have to write something that would do the synchronization.

your summary of steps in the flow is exactly what we require - you mention it will be 5 policies or so - please would you be able to provide more details on what those policies are and how to string them together

  1. ServiceCallout to call Azure AD. I assume there is an HTTP-accessible endpoint.
  2. AssignMessage/AssignVariable (with jsonpath) to extract the returned JWT
  3. VerifyJWT to verify the JWT is signed by Azure
  4. OAuthV2/GenerateAccessToken to generate a new access token, associate attributes (claims) to it, and send it back to the original caller

I don't think it's much more complicated than that. Maybe a little error handling. I don't believe there is an existing blog post or screencast showing this. But you should be able to construct it. Just go step by step.

Good luck.

Hi dchiesa - Any feedback on this?

@Dino-at-Google I read your statement:

'Apigee Edge is the gateway. The backend api server need not have either the opaque token nor the JWT. Basically the backend (upstream?) API server is expected to trust Apigee Edge. This may be predicated on a mutual-TLS connection. If appropriate, Apigee Edge can propagate some subset of the claims on the token to the backend system - such as client identifier, group membership identifier, or similar. But this is information that is trusted - it need not be validated by the backend server.'

My company is looking into Apigee and will have the same setup that is described in this thread. Our security team wants Apigee to pass the Azure AD JWT token, that you store in cache, to the backend API server so it can perform OAuth checks.

Is there a policy that can pull the Azure AD token from cache and send to backend API service?