Backend authentication but have Apigee mint and provide JWTs to resource owners

Hi,

Is it possible for the following flows to be modeled in Apigee?

  1. Client App (a website / mobile app = the client) uses client grant (API Key) to submit end-user (the resource owner) credentials as JSON to a proxy endpoint
  2. Proxy endpoint
    1. verifies API key
    2. makes a call out to back end API to verify credentials sent (the JSON)
  3. If back end API returns with a success message
    1. Mint a new JWT Token
    2. Embed certain user details sent by my back end API (roles / custom user identifier) into JWT
    3. Send JWT token back to caller (a website / mobile app)
  4. If back end API returns with a 401 message - send that through to caller

Resource use

  1. Apigee proxy to resource verifies JWT Token
  2. If valid extracts claims in JWT (roles / custom user identifier)
  3. Calls target while embedding the claims into the header

I have read that theoretically this is possible - referred to as three legged oAuth and Custom claims can be embedded into JWT and extracted at subsequent requests.

Very new to Apigee and trying to work out what the steps / policies I should be using to try and simulate this model in Apigee

Also keen to hear reasons why such an approach is either sound / not so sound from a security point of view.

Thanks in advance.

Solved Solved
1 5 1,184
1 ACCEPTED SOLUTION

Yes it is quite possible to model those flows in Apigee Edge.

The thing you are describing is not "three legged OAuth". The three legged approach is one that involves 302 redirects between app, OAuth Server(Apigee) and user login server. In the three legged flow, neither the client-side app nor the OAuth endpoint ever handle User credentials. Three legged is like this:

  1. third party app sends a request for /authorize to OAuth Server
  2. OAuth Server (in our case Apigee Edge) sends 302 redirect to app which opens a browser window to the login experience. The user authenticates to the login experience. This login form is branded so that the user understands it is coming from the ID provider.
  3. As a followon to the login , the login server asks for user consent: "Do you consent to allowing app A to do X, Y, and Z with your data?" Because consent follows login, this is sometimes call the "login and consent" server. Mere authentication does not imply consent, so that if the user has an active browser session, "login" can be skipped, but consent cannot be skipped. (unless there is a historical record of the user previously granting consent)
  4. When the user logs in, and grants consent, the login-and-consent server sends back a 302 with an authorization code to the user-agent. This 302 points back to the OAuth Server.
  5. The OAuth Server receives that request, verifies the authorization code, and then creates a token that is valid for this combination of user+app. This token gets returned to the app.

In this flow, the app never sees user creds. The OAuth server never sees auth creds.

What you have described is different. Your flow calls for the app/client to collect user credentials and send them to the OAuth Server. In OAuth speak this is called the "password grant flow". Both the app and the OAuth server handle user credentials, therefore both are implicitly trusted. Therefore the app must be provided by the same vendor as the service (resource manager). In this respect it is 2-legged flow.

Apigee Edge can be used to implement either the 2-legged password-grant flow, or the 3-legged authorization-code flow.

Apigee Edge can generate opaque OAuth tokens, and also JWT. Either can include arbitrary claims. In the case of opaque auth tokens, Apigee call these arbitrary claims "custom attributes". You can attach attributes to the opaque token at the time it is created. Such a token looks like this:

s93784hreerghksdhfshdsshf

...and is really a random string, which serves as a pointer to the metadata stored with the token, in the Apigee Edge token store.

As you can imagine, the difference is the JWT can be verified by anybody, any party that has access to the public key of the signer. The opaque oauth token is different - only the issuing party (Apigee Edge) can verify the token.

There are advantages and disadvantages to either kind of token. And because you use one type of token does not mean you won't want to use the other. Often the signed JWT is used for identification of the USER to the APP. Conversely, the opaque token could be sent by the app to the OAuth server within service requests, and the OAuth server can use that to authenticate the request. In fact , OpenID connect allows (encourages?) the use of both, in the way I just described.

The mobile app might receive the JWT id token from the oauth server, and could then self-verify that token and then it would be able to rely on the information contained therein - trust that the email address asserted in the token is the actual email address of the authenticated user. In this approach, the app won't transmit the JWT to Apigee. The JWT is intended for consumption by the app itself. Instead when requesting service, the app sends the opaque OAuth token to Apigee Edge, and Apigee Edge can verify that.

The JWT and opaque OAuth token may have different lifetimes. The opaque token might be 32 characters, whereas the JWT is 512 characters or more (depending on the claims included within it).

While there are advantages to using the opaque token, you could also use a JWT as an access token. It might not be the same as the JWT id token, but it might be a complement to that ID token.

Whether you use the opaque token or the JWT as an access token, when the app sends that token to Apigee Edge, the claims attached to the token are available for use by Apigee Edge when making authorization or routing decisions. And as well, Apigee Edge could embed those claims into HTTP Headers when making requests to the backend.

As to HOW to do all of that, well that's a longer story.

View solution in original post

5 REPLIES 5

Yes it is quite possible to model those flows in Apigee Edge.

The thing you are describing is not "three legged OAuth". The three legged approach is one that involves 302 redirects between app, OAuth Server(Apigee) and user login server. In the three legged flow, neither the client-side app nor the OAuth endpoint ever handle User credentials. Three legged is like this:

  1. third party app sends a request for /authorize to OAuth Server
  2. OAuth Server (in our case Apigee Edge) sends 302 redirect to app which opens a browser window to the login experience. The user authenticates to the login experience. This login form is branded so that the user understands it is coming from the ID provider.
  3. As a followon to the login , the login server asks for user consent: "Do you consent to allowing app A to do X, Y, and Z with your data?" Because consent follows login, this is sometimes call the "login and consent" server. Mere authentication does not imply consent, so that if the user has an active browser session, "login" can be skipped, but consent cannot be skipped. (unless there is a historical record of the user previously granting consent)
  4. When the user logs in, and grants consent, the login-and-consent server sends back a 302 with an authorization code to the user-agent. This 302 points back to the OAuth Server.
  5. The OAuth Server receives that request, verifies the authorization code, and then creates a token that is valid for this combination of user+app. This token gets returned to the app.

In this flow, the app never sees user creds. The OAuth server never sees auth creds.

What you have described is different. Your flow calls for the app/client to collect user credentials and send them to the OAuth Server. In OAuth speak this is called the "password grant flow". Both the app and the OAuth server handle user credentials, therefore both are implicitly trusted. Therefore the app must be provided by the same vendor as the service (resource manager). In this respect it is 2-legged flow.

Apigee Edge can be used to implement either the 2-legged password-grant flow, or the 3-legged authorization-code flow.

Apigee Edge can generate opaque OAuth tokens, and also JWT. Either can include arbitrary claims. In the case of opaque auth tokens, Apigee call these arbitrary claims "custom attributes". You can attach attributes to the opaque token at the time it is created. Such a token looks like this:

s93784hreerghksdhfshdsshf

...and is really a random string, which serves as a pointer to the metadata stored with the token, in the Apigee Edge token store.

As you can imagine, the difference is the JWT can be verified by anybody, any party that has access to the public key of the signer. The opaque oauth token is different - only the issuing party (Apigee Edge) can verify the token.

There are advantages and disadvantages to either kind of token. And because you use one type of token does not mean you won't want to use the other. Often the signed JWT is used for identification of the USER to the APP. Conversely, the opaque token could be sent by the app to the OAuth server within service requests, and the OAuth server can use that to authenticate the request. In fact , OpenID connect allows (encourages?) the use of both, in the way I just described.

The mobile app might receive the JWT id token from the oauth server, and could then self-verify that token and then it would be able to rely on the information contained therein - trust that the email address asserted in the token is the actual email address of the authenticated user. In this approach, the app won't transmit the JWT to Apigee. The JWT is intended for consumption by the app itself. Instead when requesting service, the app sends the opaque OAuth token to Apigee Edge, and Apigee Edge can verify that.

The JWT and opaque OAuth token may have different lifetimes. The opaque token might be 32 characters, whereas the JWT is 512 characters or more (depending on the claims included within it).

While there are advantages to using the opaque token, you could also use a JWT as an access token. It might not be the same as the JWT id token, but it might be a complement to that ID token.

Whether you use the opaque token or the JWT as an access token, when the app sends that token to Apigee Edge, the claims attached to the token are available for use by Apigee Edge when making authorization or routing decisions. And as well, Apigee Edge could embed those claims into HTTP Headers when making requests to the backend.

As to HOW to do all of that, well that's a longer story.

Wow! Thanks for all that info - learned heaps in that one post

I was under the assumption that it was three legged oAuth as there were three parties here

(1) app (2) Apigee and (3) my api

As the app is trusted (in house) the password flow does seem to suffice for my use case

In my case I believe both opaque tokens are also fine as long as the encoded information can be retrieved later - and also passed along during a token refresh flow!

RE: “As to HOW to do all of that, well that's a longer story.”

- total noob to Apigee so would love to hear your thoughts and/or any pointers in the right direction...

Even just a list of the sequence of policies to use would be great!

Thanks in advance

Here's a quick tutorial on the topic

https://community.apigee.com/articles/17969/oauth-20-password-grant.html

I just looked, and frustratingly, I don't have a working example published to GitHub...

I'll get one up there, pretty soon.

Pradeep,

I've updated this repo with a lab exercise on password-grant OAuth.

https://github.com/DinoChiesa/devjam3-20170405/tree/master/Labs/Appendix/Securing-APIs-with-OAuth-pa...

Thanks @Dino will take a look.

Btw - I've been experimenting as well.

This is what I have come up

PROXY : url?Key={KEY}&grant_type=password

Authorisation : base64(clientId:clientSecret)

PreFlow -> Request

  • Verify API Key
  • Assign Message - to remove key
  • Service CallOut
    • What I found was that by default there are a lot of XML that gets put in - you need to clear it out to the point that it's just got your Target Connection for the backend IDP and let it take the incoming payload. When I didn't the Service CallOut step kept failing

PreFlow ->Response

  • ExtractVariable
    • To read the response from the backend IDP and store in variables - used in minting token step

PostFlow ->Response

  • oAuthV2.GenerateAccessToken
    • Supply Fields : UserName, Password from incoming request variables
    • Attributes : Custom Attributes from ServiceCall Out Response
    • <SupportedGrantTypes>
      <GrantType>password</GrantType>
      </SupportedGrantTypes>
      <GrantType>request.queryparam.grant_type</GrantType>
    • <GenerateResponse enabled="true"/>

Fundamentally while this works - the biggest security underpinning I see is that the password grant_type is only going to work for

  1. apps developed in house
  2. and where the initial token generation happens via the back channel - as client keys are quite visible

In fact I would try and lock down the proxy to only certain trusted IPs if possible