password form-param encryption and decryption

I have a requirement where password form-param in password grant type should be encrypted. I would like to know how to achieve this in apigee-x.@dchiesa please help.

4 1 59
1 REPLY 1

Well that's a simple question!  As with a lot of my answers here, the answer is a bit longer.

If you pass the password in "clear text", then it is actually encrypted, but at the transport-layer, via TLS.  So it is actually encrypted before transmission, and decrypted after reception, but at the TLS layer.  The TLS termination point  will be different, depending on the configuration of your Apigee service.

If you would like the password to be encrypted at the application layer, then you have some options.  

  1. use an encrypted JWT.  The caller / initiator assembles an encrypted JWT, specifying the password as one of the claims in the encrypted paylaod, and then transmits THAT encrypted blob.  The receiver, Apigee in this case, decrypts the JWT and can then access the password.  In Apigee you can decrypt an encrypted JWT with the built-in VerifyJWT policy. It is up to the client / caller to figure out how to create the encrypted JWT. That would be different depending on the platform used by the client - Python, Java, golang, JavaScript, etc.
  2. Use "simple" encryption.  This is very similar  to the above, except it is simpler, though maybe less widely adopted, though with more options you have the chance to get things wrong.  Rather than using the JWT model of a dot-concatenated header, payload, IV, etc etc, those parameters would be "locked" by your approach.   You can use RSA or AES easily.  In Apigee, you can RSA-decrypt a blob with this java callout.  or AES-decrypt with this callout. As above, it is up to you to figure out how to geenrate the cryptotext on the client side. 

JWT is probably "safer" because there are libraries that do the right thing for you, whereas with "simple" encryption, you have to make decisions and implement things yourself. But In either case, the security of the approach depends on proper key management

Encrypted JWT can use symmetric or asymmetric algorithms. Symmetric will use an AES-based algorithm, which means a shared secret. Something both the client and the receiver (Apigee) share. The obvious thing to use here is the client secret. Or it could be something else.  If you use the client secret, you need to insure you're not transmitting the client secret, in base64-encoded form in the Basic Auth header.  That would defeat the encryption entirely, I hope you can see why. 

Asymmetric algorithms use public/private keypairs.  You have options for Elliptic Curve or RSA here. RSA is easy and well-known.  EC is also just fine. In either case, you need to generate a keypair, and then publish the public key (maybe via JWKS?), and keep the private key private, and accessible to the Apigee proxy. (Maybe via Google Cloud Secret Manager)  Just a reminder: In asymmetric crypto, the public key is used during encryption; the private key during decryption.  So the public key can be shared widely. Whatever gets encrypted via a public key, can be decrypted only by the holder of the private key. 

The same applies to the "simple encryption" cases.

===

One way to avoid the issue entirely is to replace "password grant" with something like "ID Token grant".  Basically the flow is, the client authenticates with an Identity Provider, like Entra ID, or Google Signin, or Firebase Auth, or Okta, etc.  And then receives the ID Token.  The client then sends the signed ID token into the /token dispensing proxy in Apigee.  Apigee uses VerifyJWT on the signed token, and if the signature verifies, Apigee uses THAT as proof that the user is authentic. As an example, see this repo for a working proxy.  This is really nice because your IDP can enforce the kind of authentication, even enforce multi-factor auth, if it likes. Apigee never handles a password.

My recommendation would be to use the last - don't send the password at all.  But that won't work for every situation.