question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

troubleshooting X-Access-Token not send to backend service (Okta, oauth2 flow, envoy, eas)

See original GitHub issue

Hello,

with help managed to run Oauth2 flow with Okta. Integration with EAS is done via “envoy.extensions.filters.http.ext_authz.v3.ExtAuthz”.

All is woking now and decided to add “envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication” and “envoy.extensions.filters.http.rbac” to be able to implement RBAC based on group claims in JWT tokens.

As i understood EAS is capable to obtain JWT tokens and populate to request headers, ie “X-Access-Token” or “Authorization”.

For some reason (probably envoy configuration) “X-Access-Token” is not set. Searching through EAS logs i see request to “/envoy/verify-params-header/” endpoint and if i interpreter that correctly, the response is 200 and appropriate headers are set, ie. “X-Access-Token”.

debug: plugin response {"statusCode":200,"statusMessage":"","body":"","cookies":[],"clearCookies":[],"headers":{"X-Access-Token":"eyJraW

If i look into connection flow from client side, i see no requests to “/envoy/verify-params-header/” endpoint. So im assuming it is “envoy.extensions.filters.http.ext_authz.v3.ExtAuthz” interacting with EAS.

Now the question. How does this really work? How and than “X-Access-Token” is set? As i cannot understand why “X-Access-Token” is not sent (or removed, etc.) to backend service (upstream in envoy§s terminology).

Thank you!

generate_config_token.js:

const jwt = require("jsonwebtoken");
const utils = require("../src/utils");

const config_token_sign_secret =
  process.env.EAS_CONFIG_TOKEN_SIGN_SECRET ||
  utils.exit_failure("missing EAS_CONFIG_TOKEN_SIGN_SECRET env variable");
const config_token_encrypt_secret =
  process.env.EAS_CONFIG_TOKEN_ENCRYPT_SECRET ||
  utils.exit_failure("missing EAS_CONFIG_TOKEN_ENCRYPT_SECRET env variable");

let config_token = {
  /**
   * future feature: allow blocking certain token IDs
   */
  //jti: <some known value>

  /**
   * using the same aud for multiple tokens allows sso for all services sharing the aud
   */
  aud: "aud_or_client_id", //should be unique to prevent cookie/session hijacking, defaults to a hash unique to the whole config
  eas: {
    // list of plugin definitions, refer to PLUGINS.md for details
    plugins: [
      {
        type: "oauth2",
        issuer: {
          authorization_endpoint: "https://zztop.oktapreview.com/oauth2/authorization_server/v1/authorize",
          token_endpoint: "https://zztop.oktapreview.com/oauth2/authorization_server/v1/token"
        },
        client: {
          client_id: "aud_or_client_id",
          client_secret: "client_secret"
        },
        scopes: ["user"],
        /**
         * static redirect URI
         * if your oauth provider does not support wildcards place the URL configured in the provider (that will return to this proper service) here
         */
        redirect_uri: "https://localhost7:10443/oauth/callback",
        features: {
          /**
           * if false cookies will be 'session' cookies
           * if true and cookies expire will expire with tokens
           */
          cookie_expiry: false,

          userinfo_expiry: 86400, // 24 hours

          /**
           * sessions become a floating window *if* tokens are being refreshed or userinfo being refreshed
           */
          session_expiry: 604800, // 7 days

          /**
           * if session_expiry is a number and this is set then sessions become a 'floating window'
           * if activity is triggered in this amount of time *before* preceeding the end of the
           * session then the expiration time is extended + session_expiry
           */
          session_expiry_refresh_window: 86400, // 24 hours

          /**
           * will re-use the same id (ie: same cookie) for a particular client if a session has expired
           */
          session_retain_id: true,

          /**
           * if the access token is expired and a refresh token is available, refresh
           */
          refresh_access_token: true,

          /**
           * fetch userinfo and include as X-Userinfo header to backing service
           */
          fetch_userinfo: false,

          userinfo: {
            provider: "oidc",
            config: {
              fetch_teams: true,
              fetch_organizations: true,
              fetch_emails: true
            }
          },

          /**
           * which token (if any) to send back to the proxy as the Authorization Bearer value
           * note the proxy must allow the token to be passed to the backend if desired
           *
           * possible values are access_token, or refresh_token
           */
          authorization_token: "access_token"
        },
        assertions: {
          /**
           * assert the token(s) has not expired
           */
          exp: true
        },
        cookie: {
          name: "_eas_localhost_session_", //default is _oeas_oauth_session
          //domain: "localhost" //defaults to request domain, could do sso with more generic domain
          //path: "/",
        }
      }
    ]
  }
};

config_token = jwt.sign(config_token, config_token_sign_secret);
const config_token_encrypted = utils.encrypt(
  config_token_encrypt_secret,
  config_token
);

//console.log("token: %s", config_token);
//console.log("");

console.log("encrypted token (for server-side usage): %s", config_token_encrypted);
console.log("");

console.log(
  "URL safe config_token: %s",
  encodeURIComponent(config_token_encrypted)
);
console.log("");

ExtAuthz config:

          http_filters:
          - name: envoy.filters.http.ext_authz
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
              transport_api_version: V3
              http_service:
                authorizationRequest:
                  allowedHeaders:
                    patterns:
                      - exact: cookie
                      - exact: X-Forwarded-Host
                      - exact: X-Forwarded-Method
                      - exact: X-Forwarded-Proto
                      - exact: X-Forwarded-Uri
                  headers_to_add:
                    - key: "x-eas-verify-params"
                      value: '{"config_token":"---reducted---"}'
                    - key: X-Forwarded-Proto
                      value: "https"
                pathPrefix: /envoy/verify-params-header
                serverUri:
                  cluster: eas
                  timeout: 2.25s
                  uri: http://eas:8080
          - name: envoy.filters.http.router

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:12 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
travisghansencommented, Jul 19, 2021

Actually, I spoof x-forwarded-uri and x-forwarded-method internally in the case of envoy so those 2 may not be actually getting sent. Sorry, forgot to mention that earlier. I do that to make the internals of eas behave the same as other proxies. The way envoy handles things is slightly different that some of the others (hence the special endpoint just for envoy setups).

The above doesn’t explain the missing -proto header though.

app.all("/envoy/verify-params-header(/*)?", async (req, res) => {
  req.headers["x-forwarded-uri"] =
    externalAuthServer.utils.get_envoy_forwarded_uri(req, 3);
  req.headers["x-forwarded-method"] = req.method;

  verifyHandler(req, res);
});
1reaction
nonefakencommented, Jul 18, 2021

I made updated “x-forwarded-proto” to lower case instead of “X-Forwarded-Proto” as you suggested, and it seems to help:

                  allowedHeaders:
                    patterns:
                      - exact: cookie
                      - exact: X-Forwarded-Host
                      - exact: X-Forwarded-Method
                      - exact: x-forwarded-proto
                      - exact: X-Forwarded-Uri
                  headers_to_add:
                    - key: "x-eas-verify-params"
                      value: '{"config_token":"t---reducted---"}'
                    #- key: X-Forwarded-Proto
                    #  value: "https"

Ill trace it tomorrow to double check, as strangely other parameters work. Have to go to sleep, as work day tomorrow.

Thank you for great project and help!

Read more comments on GitHub >

github_iconTop Results From Across the Web

OpenID Connect & OAuth 2.0 API - Okta Developer
This request authenticates the user and returns tokens along with an authorization grant to the client application as a part of the callback...
Read more >
Okta authorization_code flow not working · Issue #867 - GitHub
1.1 configured in my kubernetes cluster and I'm trying to make the authorization code flow to work. But looks like the /token endpoint...
Read more >
Protecting web applications via Envoy OAuth2 filter
Modern applications rely on authorizing user's access to their application. ... is to embed a OAuth2 client/library into each micro service to help...
Read more >
API Authorization at the Gateway with Apigee, Okta and OPA ...
Now we'll create an Okta API token that our Frontend service can use to authenticate requests to Okta APIs. To create an authentication...
Read more >
OAuth2 — envoy 1.25.0-dev-317efa documentation
When the authn server validates the client and returns an authorization token back to the OAuth filter, no matter what format that token...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found