1

I want to try out Envoy JWT authentication with a local JSON Web Key Set as an inline string. As an algorithm I want to use HS256, because the key is only needed for my Service that generates the JWT and Envoy for enforcing rules, so not much sharing with more services.
Below is an excerpt of my Envoy config that configures the authentication rules:

http_filters:
  - name: envoy.filters.http.jwt_authn
    typed_config:
      "@type": "type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication"
      providers:
        main_auth:
          forward_payload_header: auth_user
          issuer: example.com
          local_jwks:
            inline_string: '{"keys":[{"kty": "oct","alg": "HS256", "use": "sig","kid": "Example Key","k": "nZeA0nwBUS-ma0oTtZfVnk8o1bjtaJZfuUMpzdEuXu4wEgeKou1klrGoWSPm4nRBNTAIwflteghMOsP9d0gtXOPNh-Fwd-0Ef1a06JGa5Zx3Uo1qmmKRLSxNGuCQY8M9qFWPyFsdMA5-1Y5EOEAnoqb02YqibGOUx6msH3uBcU-jMyY90ysEboN8s03gBl0FmhgWTAc25JNxF4eF4dt2oUF4Z48YHuk5U6lR6oNoJ38iP1wLBAz70d3kFgq_MtfojsKcuHk2HzBESx5fynUhc2ZFdXm-hg0zHFqFoHYd5wKva06bjIv61yd6lNe5YGi5wYbPNHO7bkg3vaWl0zhE5w"}]}'
      rules:
        # Not JWT verification is needed for the /auth route
        - match:
            prefix: /auth
        # JWT verification is required for the /profile route
        - match:
            prefix: /profile
          requires:
            provider_name: main_auth

I'm not quite familiar with JSON web key sets and therefor I'm not sure what property of the set to use in my application as the secret to generate the key. I tried using the k property of the set as my secret for the JWT but the request still fails with the message: Jwt verification fails.

This is how I generate the key with the npm jsonwebtoken package, I have just copied the k property of the Key Set as the secret:

jwt.sign(
  {role: 'ADMIN'}, 
  'nZeA0nwBUS-ma0oTtZfVnk8o1bjtaJZfuUMpzdEuXu4wEgeKou1klrGoWSPm4nRBNTAIwflteghMOsP9d0gtXOPNh-Fwd-0Ef1a06JGa5Zx3Uo1qmmKRLSxNGuCQY8M9qFWPyFsdMA5-1Y5EOEAnoqb02YqibGOUx6msH3uBcU-jMyY90ysEboN8s03gBl0FmhgWTAc25JNxF4eF4dt2oUF4Z48YHuk5U6lR6oNoJ38iP1wLBAz70d3kFgq_MtfojsKcuHk2HzBESx5fynUhc2ZFdXm-hg0zHFqFoHYd5wKva06bjIv61yd6lNe5YGi5wYbPNHO7bkg3vaWl0zhE5w',
  { issuer: 'example.com' }
);

What property of the set do I have to use as the secret in my application so that the JWT can get accepted by Envoy?
I generated my example Key set with this tool: https://mkjwk.org/

Edit

This is a JWK I generated and I'm not able to decode it either as a base64 string or base64URL string.

{
  "keys": [
    {
      "kty": "oct",
      "kid": "LqDTw3xmtazF_pIdZMDRfE2XRDR8MRD_yxLPWaZoyWA",
      "use": "sig",
      "alg": "HS256",
      "k": "3D7zGRLWSumeweTpG6AkYAQ4KpLZVzv8FygYsZD7fTOYBj0XaI26P4lpZpE1EZPlVPcYOBOmzqRfnUrcdUh43H_wIYax7avrdgAFjD-69SWY7Yo4FkY4yOIpq4xzBA7yEb8_Y9SS3to5GBcZKygp3ybyK-6fLK5HNDAD8dR-VUDeg0DARyIQaBZjhXe2DW-2VjdE6llandUavn2Hd_pwUZNH6zYPW9ObJlk_CdOwMxlelH0brGc4Ja119ptgJTcqauUGQIYnizulbwYBgsQAXEyAChw07-HL7_FDQbqHPA_MxyoNk_ahNItD5GcKIoo1m5esQQeO7fbFkZhESY85Dw"
    }
  ]
}

This is how I generate a JWK with Node.js

const fs = require("fs");
const jose = require("node-jose");

const main = () => {
  const keyStore = jose.JWK.createKeyStore();
  keyStore
    .generate("oct", 2048, { alg: "HS256", use: "sig" })
    .then((result) => {
      fs.writeFileSync(
        "keys.json",
        JSON.stringify(keyStore.toJSON(true), null, "  ")
      );
    });
};

main();

JonasLevin
  • 1,592
  • 1
  • 20
  • 50
  • k is the right property, but I think when you sign the token, you have to Base64 decode k – jps Dec 09 '21 at 20:42
  • I will try it out, thanks for the tip – JonasLevin Dec 09 '21 at 20:46
  • I just tried base64 encoding the `k` value and using it as the secret, but `Envoy` still fails to verify the request. You wrote _Base64 decode k_ but the k value is not in Base64 format so I can't decode it. You probably ment to encode it to base64, which I tried. – JonasLevin Dec 09 '21 at 21:13
  • sorry I was not precise enough. The value k is in fact Base64Url encoded (a variant of base64) and you need to decode it. – jps Dec 09 '21 at 21:18
  • I have edited my question and added an example JWK and the way I generate it. I tried various online base64URL decoders and it's just not working. – JonasLevin Dec 09 '21 at 23:11
  • 1
    I think there might be a misunderstanding regarding the base64url decoding. The key is in fact base64url encoded. It has 342 characters, each character represents 6 bits, so togehter these are 2052 bit, decoded it will be 256 bytes (2048 bits) + 4 bits to be ignored. But of course the result of the decoding is binary (every resulting byte can have any value between 0 and 255 decimal) and therefore not printable and the gibberish that an online decoder maybe shows can't really be used. You have to convert it in your code. Pseudocode: ` secret = base64.urldecode(k)` , secret is a byte array. – jps Dec 10 '21 at 08:15
  • And if you have no base64url decoder, you can just replace `-` with `+`, `_` with `/` and add padding characters (`=`), in this case 2 of them, to get a base64 string. – jps Dec 10 '21 at 08:26
  • Thanks for your helpful comments. I now finally got it to work by first generating a secret hex string. And then base64 encoding the secret and using the base64 version as the `k` parameter. – JonasLevin Dec 10 '21 at 21:24
  • I answered a very similar question yesterday and I think it covers everything you asked here. And thanks for confirming that it worked. Glad to know you found a solution. – jps Dec 14 '21 at 10:04

0 Answers0