Skip to content

Envoy proxy

Envoy is a proxy that sits in front of Vascular Inbox. SDK traffic goes to Envoy first; Envoy forwards allowed requests to Vascular.

Why Envoy is needed

Web SDKs (React, React Native in the browser) cannot call Vascular Inbox on port 3000 directly. Browsers need a proxy that handles CORS and web-compatible routing. Point the SDK at Envoy on port 8081.

Your own authentication before Vascular — optional. If you want every SDK request validated by your login or identity system (not only Vascular API key and app key), the SDK can send a session-token on each call. Envoy sends that token to your authentication service first; only approved requests reach Vascular Inbox. You build and run that service — it is not part of Vascular. See Authentication.

Native SDKs (Flutter, Android, iOS) without a session-token may connect to Vascular Inbox on port 3000 directly and do not need Envoy.

ScenarioSDKsEnvoy listener
Web SDKsReact, React Native (web)8081 — required
Your custom authenticationWeb and/or native (with session-token)8081 (web) or 8082 (native) — required

Request flow

Web SDKs (API key + app key only)

text
Web SDK  →  Envoy (:8081)  →  Vascular Inbox

Your authentication, then Vascular (session-token enabled)

text
Vascular SDK  →  Envoy  →  your authentication service  →  Vascular Inbox

Placeholders

Copy one configuration below to envoy.yaml and replace placeholders before deploying (for example with envsubst):

PlaceholderDescriptionExample
${vascular_upstream_HOST}Hostname of the Vascular servicevascular-inbox
${vascular_upstream_PORT}Port of the Vascular service3000
${ENVOY_API_DOMAIN}Envoy API domain name (hostname clients call)envoy.your-domain.com
${CORS_ALLOW_ORIGIN}Allowed browser frontend origin (web SDK configs only)https://app.your-domain.com
${auth_filter_HOST}Hostname of your authentication service (session token configs only)my-auth-service
${auth_filter_PORT}Port of your authentication service (session token configs only)9001

SDK endpoints

ConfigurationExample endpoint
Web SDKhttps://envoy.your-domain.com:8081
Web SDK + your authenticationhttps://envoy.your-domain.com:8081
Native SDK + your authenticationhttps://envoy.your-domain.com:8082
Native SDK (no Envoy)https://vascular.your-domain.com:3000

Ports (8081, 8082, 3000) and hostnames are examples — configure them in your Envoy and Vascular Inbox deployment.

Do not point web SDKs at the Vascular Inbox hostname or port.

Configurations

1. Web SDKs — API key and app key only

Listener 8081 for React and React Native (web). No custom authentication service. Native SDKs use Vascular Inbox on port 3000 directly.

Download web-sdks.yaml

yaml
static_resources:
  listeners:
    - name: listener_8081
      address:
        socket_address:
          address: 0.0.0.0
          port_value: 8081
      filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                stat_prefix: ingress_http
                codec_type: AUTO

                http_filters:
                  - name: envoy.filters.http.grpc_web
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb

                  - name: envoy.filters.http.cors
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors

                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: backend
                      domains: ["${ENVOY_API_DOMAIN}"]
                      cors:
                        allow_origin_string_match:
                          - exact: "${CORS_ALLOW_ORIGIN}"
                        allow_methods: GET, PUT, DELETE, POST, OPTIONS
                        allow_headers: content-type,authorization,x-requested-with,x-grpc-web,x-user-agent,app-key,api-key,grpc-timeout
                        expose_headers: grpc-status,grpc-message,grpc-status-details-bin
                        max_age: "1728000"
                      routes:
                        - match:
                            prefix: /
                          route:
                            cluster: vascular_upstream
                            timeout: 30s

  clusters:
    - name: vascular_upstream
      type: STRICT_DNS
      dns_lookup_family: V4_ONLY
      connect_timeout: 5s
      lb_policy: ROUND_ROBIN
      typed_extension_protocol_options:
        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
          "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
          explicit_http_config:
            http2_protocol_options: {}
      load_assignment:
        cluster_name: vascular_upstream
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: ${vascular_upstream_HOST}
                      port_value: ${vascular_upstream_PORT}
2. Web SDKs + your authentication — session token on web only

Listener 8081. Use when only web clients send a session-token and you validate it with your own service before Vascular Inbox.

Download web-sdks-auth-filter.yaml

yaml
static_resources:
  listeners:
    - name: listener_8081
      address:
        socket_address:
          address: 0.0.0.0
          port_value: 8081
      filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                stat_prefix: ingress_http
                codec_type: AUTO

                http_filters:
                  - name: envoy.filters.http.lua
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
                      inline_code: |
                        function envoy_on_response(response_handle)
                          local status = response_handle:headers():get(":status")
                          if status ~= "401" and status ~= "403" then
                            return
                          end

                          local grpc_status = "16"
                          local grpc_message = "Unauthenticated"
                          if status == "403" then
                            grpc_status = "7"
                            grpc_message = "Permission%20denied"
                          end

                          response_handle:headers():replace(":status", "200")
                          response_handle:headers():replace("content-type", "application/grpc-web-text+proto")
                          response_handle:headers():replace("grpc-status", grpc_status)
                          response_handle:headers():replace("grpc-message", grpc_message)
                          response_handle:body(true):setBytes("")
                        end

                  - 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:
                        server_uri:
                          uri: http://${auth_filter_HOST}:${auth_filter_PORT}
                          cluster: auth_filter
                          timeout: 5s
                        authorization_request:
                          allowed_headers:
                            patterns:
                              - exact: session-token
                              - exact: app-key
                              - exact: api-key
                              - exact: content-type
                              - exact: x-grpc-web
                              - exact: grpc-timeout
                      failure_mode_allow: false

                  - name: envoy.filters.http.grpc_web
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb

                  - name: envoy.filters.http.cors
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors

                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: backend
                      domains: ["${ENVOY_API_DOMAIN}"]
                      cors:
                        allow_origin_string_match:
                          - exact: "${CORS_ALLOW_ORIGIN}"
                        allow_methods: GET, PUT, DELETE, POST, OPTIONS
                        allow_headers: content-type,authorization,x-requested-with,x-grpc-web,x-user-agent,app-key,api-key,session-token,grpc-timeout
                        expose_headers: grpc-status,grpc-message,grpc-status-details-bin
                        max_age: "1728000"
                      routes:
                        - match:
                            prefix: /
                          route:
                            cluster: vascular_upstream
                            timeout: 30s

  clusters:
    - name: auth_filter
      type: STRICT_DNS
      connect_timeout: 5s
      lb_policy: ROUND_ROBIN
      typed_extension_protocol_options:
        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
          "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
          explicit_http_config:
            http_protocol_options: {}
      load_assignment:
        cluster_name: auth_filter
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: ${auth_filter_HOST}
                      port_value: ${auth_filter_PORT}

    - name: vascular_upstream
      type: STRICT_DNS
      dns_lookup_family: V4_ONLY
      connect_timeout: 5s
      lb_policy: ROUND_ROBIN
      typed_extension_protocol_options:
        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
          "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
          explicit_http_config:
            http2_protocol_options: {}
      load_assignment:
        cluster_name: vascular_upstream
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: ${vascular_upstream_HOST}
                      port_value: ${vascular_upstream_PORT}
3. All SDKs + your authentication — session token on web and native

Listeners 8081 (web, with CORS) and 8082 (Flutter, Android, iOS). Use when every SDK sends a session-token validated by your service before Vascular Inbox.

Download all-sdks-auth-filter.yaml

yaml
static_resources:
  listeners:
    - name: listener_8081
      address:
        socket_address:
          address: 0.0.0.0
          port_value: 8081
      filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                stat_prefix: ingress_http
                codec_type: AUTO

                http_filters:
                  - name: envoy.filters.http.lua
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
                      inline_code: |
                        function envoy_on_response(response_handle)
                          local status = response_handle:headers():get(":status")
                          if status ~= "401" and status ~= "403" then
                            return
                          end

                          local grpc_status = "16"
                          local grpc_message = "Unauthenticated"
                          if status == "403" then
                            grpc_status = "7"
                            grpc_message = "Permission%20denied"
                          end

                          response_handle:headers():replace(":status", "200")
                          response_handle:headers():replace("content-type", "application/grpc-web-text+proto")
                          response_handle:headers():replace("grpc-status", grpc_status)
                          response_handle:headers():replace("grpc-message", grpc_message)
                          response_handle:body(true):setBytes("")
                        end

                  - 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:
                        server_uri:
                          uri: http://${auth_filter_HOST}:${auth_filter_PORT}
                          cluster: auth_filter
                          timeout: 5s
                        authorization_request:
                          allowed_headers:
                            patterns:
                              - exact: session-token
                              - exact: app-key
                              - exact: api-key
                              - exact: content-type
                              - exact: x-grpc-web
                              - exact: grpc-timeout
                      failure_mode_allow: false

                  - name: envoy.filters.http.grpc_web
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb

                  - name: envoy.filters.http.cors
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors

                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: backend
                      domains: ["${ENVOY_API_DOMAIN}"]
                      cors:
                        allow_origin_string_match:
                          - exact: "${CORS_ALLOW_ORIGIN}"
                        allow_methods: GET, PUT, DELETE, POST, OPTIONS
                        allow_headers: content-type,authorization,x-requested-with,x-grpc-web,x-user-agent,app-key,api-key,session-token,grpc-timeout
                        expose_headers: grpc-status,grpc-message,grpc-status-details-bin
                        max_age: "1728000"
                      routes:
                        - match:
                            prefix: /
                          route:
                            cluster: vascular_upstream
                            timeout: 30s

    - name: listener_8082
      address:
        socket_address:
          address: 0.0.0.0
          port_value: 8082
      filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                stat_prefix: ingress_grpc
                codec_type: AUTO

                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:
                        server_uri:
                          uri: http://${auth_filter_HOST}:${auth_filter_PORT}
                          cluster: auth_filter
                          timeout: 5s
                        authorization_request:
                          allowed_headers:
                            patterns:
                              - exact: session-token
                              - exact: app-key
                              - exact: api-key
                              - exact: content-type
                              - exact: grpc-timeout
                      failure_mode_allow: false

                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

                route_config:
                  name: grpc_route
                  virtual_hosts:
                    - name: backend
                      domains: ["${ENVOY_API_DOMAIN}"]
                      routes:
                        - match:
                            prefix: /
                          route:
                            cluster: vascular_upstream
                            timeout: 30s

  clusters:
    - name: auth_filter
      type: STRICT_DNS
      connect_timeout: 5s
      lb_policy: ROUND_ROBIN
      typed_extension_protocol_options:
        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
          "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
          explicit_http_config:
            http_protocol_options: {}
      load_assignment:
        cluster_name: auth_filter
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: ${auth_filter_HOST}
                      port_value: ${auth_filter_PORT}

    - name: vascular_upstream
      type: STRICT_DNS
      dns_lookup_family: V4_ONLY
      connect_timeout: 5s
      lb_policy: ROUND_ROBIN
      typed_extension_protocol_options:
        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
          "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
          explicit_http_config:
            http2_protocol_options: {}
      load_assignment:
        cluster_name: vascular_upstream
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: ${vascular_upstream_HOST}
                      port_value: ${vascular_upstream_PORT}

Vascular Platform developer documentation