# Outbound Routes

Our outbound connection uses an outbound/forward [proxy](/vault/http-proxy.md).

## What does it allow you to do?

* Like the [inbound connection](/vault/http-proxy/inbound-connection.md), the outbound/forward proxy allows you to rewrite requests and responses on the fly.
* Lets you operate on data outside of the scope of your backend systems.
* Set/Change/Strip Headers - perform any operation on the payload.
* Modify the payload, even if it's not a strict redaction/replacement.
* Perform Edge Computing, as needed for computing outside of the scope of your system (enterprise plans)
* Adds an additional layer of security requiring proxy-authorization credentials and a root certificate to be set.
* Is used to integrate into third party services and allows for configurations that are processor specific as mentioned in the [integrations](/vault/http-proxy/integration-templates.md) page.
* Our outbound/forward proxy also allows for IP Anonymization as an additional upgrade.

## How does it work?

The outbound/forward proxy directs traffic between your server (outbound) traffic, the VGS vault (where sensitive data is stored), and your third party integration

**Example:**

* BEFORE: server.foo.com → api.worldpay.com
* AFTER: server.foo.com → `<VAULT_ID>`.`<ENVIRONMENT>`.verygoodproxy.com → api.worldpay.com

To achieve that you should set your server to send traffic through our outbound/forward proxy and create routes, filters and operations for your different API endpoints.

## TLS Certificates

The outbound/forward proxy requires a TLS certificate. We have a different server certificate for each environment, **SANDBOX** and **LIVE**. You can find these certificates within the 'Code snippets' section of your dashboard.

## Code Samples

1. Download and use appropriate TLS certificate for your vault environment to use in your application.&#x20;

<details>

<summary>sandbox.pem</summary>

```bash
-----BEGIN CERTIFICATE-----
MIID2TCCAsGgAwIBAgIHAN4Gs/LGhzANBgkqhkiG9w0BAQ0FADB5MSQwIgYDVQQD
DBsqLnNhbmRib3gudmVyeWdvb2Rwcm94eS5jb20xITAfBgNVBAoMGFZlcnkgR29v
ZCBTZWN1cml0eSwgSW5jLjEuMCwGA1UECwwlVmVyeSBHb29kIFNlY3VyaXR5IC0g
RW5naW5lZXJpbmcgVGVhbTAgFw0xNjAyMDkyMzUzMzZaGA8yMTE3MDExNTIzNTMz
NloweTEkMCIGA1UEAwwbKi5zYW5kYm94LnZlcnlnb29kcHJveHkuY29tMSEwHwYD
VQQKDBhWZXJ5IEdvb2QgU2VjdXJpdHksIEluYy4xLjAsBgNVBAsMJVZlcnkgR29v
ZCBTZWN1cml0eSAtIEVuZ2luZWVyaW5nIFRlYW0wggEiMA0GCSqGSIb3DQEBAQUA
A4IBDwAwggEKAoIBAQDI3ukHpxIlDCvFjpqn4gAkrQVdWll/uI0Kv3wirwZ3Qrpg
BVeXjInJ+rV9r0ouBIoY8IgRLak5Hy/tSeV6nAVHv0t41B7VyoeTAsZYSWU11deR
DBSBXHWH9zKEvXkkPdy9tgHnvLIzui2H59OPljV7z3sCLguRIvIIw8djaV9z7FRm
KRsfmYHKOBlSO4TlpfXQg7jQ5ds65q8FFGvTB5qAgLXS8W8pvdk8jccmuzQXFUY+
ZtHgjThg7BHWWUn+7m6hQ6iHHCj34Qu69F8nLamd+KJ//14lukdyKs3AMrYsFaby
k+UGemM/s2q3B+39B6YKaHao0SRzSJC7qDwbWPy3AgMBAAGjZDBiMB0GA1UdDgQW
BBRWlIRrE2p2P018VTzTb6BaeOFhAzAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQE
AwIBtjAjBgNVHSUEHDAaBggrBgEFBQcDAQYIKwYBBQUHAwIGBFUdJQAwDQYJKoZI
hvcNAQENBQADggEBAGWxLFlr0b9lWkOLcZtR9IDVxDL9z+UPFEk70D3NPaqXkoE/
TNNUkXgS6+VBA2G8nigq2Yj8qoIM+kTXPb8TzWv+lrcLm+i+4AShKVknpB15cC1C
/NJfyYGRW66s/w7HNS20RmrdN+bWS0PA4CVLXdGzUJn0PCsfsS+6Acn7RPAE+0A8
WB7JzXWi8x9mOJwiOhodp4j41mv+5eHM0reMh6ycuYbjquDNpiNnsLztk6MGsgAP
5C59drQWJU47738BcfbByuSTYFog6zNYCm7ACqbtiwvFTwjneNebOhsOlaEAHjup
d4QBqYVs7pzkhNNp9oUvv4wGf/KJcw5B9E6Tpfk=
-----END CERTIFICATE-----
```

</details>

<details>

<summary>live.pem</summary>

```bash
-----BEGIN CERTIFICATE-----
MIID0jCCArqgAwIBAgIGPraFBmGCMA0GCSqGSIb3DQEBDQUAMHYxITAfBgNVBAMM
GCoubGl2ZS52ZXJ5Z29vZHByb3h5LmNvbTEhMB8GA1UECgwYVmVyeSBHb29kIFNl
Y3VyaXR5LCBJbmMuMS4wLAYDVQQLDCVWZXJ5IEdvb2QgU2VjdXJpdHkgLSBFbmdp
bmVlcmluZyBUZWFtMCAXDTE2MDIwOTIzNTMzNloYDzIxMTcwMTE1MjM1MzM2WjB2
MSEwHwYDVQQDDBgqLmxpdmUudmVyeWdvb2Rwcm94eS5jb20xITAfBgNVBAoMGFZl
cnkgR29vZCBTZWN1cml0eSwgSW5jLjEuMCwGA1UECwwlVmVyeSBHb29kIFNlY3Vy
aXR5IC0gRW5naW5lZXJpbmcgVGVhbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAIaWead09ni5HVb6Z35MblQGzwQChshwO120nfyBsAUCGfK2SsIjFrV3
Nn0zlFn9h4SHplJPtxLHPiqFQLplv9sH4m78mK7EQ0I5CRPBc0FieOyFH5+UXZOv
Pl1NHstiAE2eHXpZQBKr7QO5h1dezILf88aK6aX9uojshxpXCrzlf2BlzYY8D4yb
IEedG61/aEjTQY+ATPW9oWDAeEIotgsC2aITw4qW3OxpP4f16QP/k8xazv23Pcha
JfQxjCnPIx1/IwQQi14qEqqGCKnreGL8KnAN1W3uz4JtRou01uAUGhhB+zkqSz9a
0P7RA0rWD5Sy34YNOiR4Dt8H8R8E+jECAwEAAaNkMGIwHQYDVR0OBBYEFBV0Bvd3
w6UGIgls8VKnooKjkmQYMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgG2MCMG
A1UdJQQcMBoGCCsGAQUFBwMBBggrBgEFBQcDAgYEVR0lADANBgkqhkiG9w0BAQ0F
AAOCAQEAEwrq/aEgjjbcRZTbtrbIOLNsEoE4YSM/ZwFeCjGP9MWmq/qX3DZECwIC
gIc6kUQEdeAe3lt7GFfc+eY0HmximG0dnISSfzzpL33HQOhud6LITT0YAfqz0hxr
NLra+XfkIRMH/vs7PqzH8siqYXxW6w52PvwX1tbMJnoq1fUGSIyxF3wZ5i+OElP9
93KcZHeI6x8KSuCc+eNAV0eovsd9XN6Pzovf9BC3/HZANndI6JJ65XJ9MygdRNF7
qR90C8HYJYGpRE6nglQi0QOTHYC7xVqrU5bxuY7znWOEGfkFug4leuKdj12TkW73
bbTjK25TlDkdvsPq4otwBkXemYcoYA==
-----END CERTIFICATE-----
```

</details>

2. Run this sample code snippet in your terminal to see an example of data revealing.

{% tabs %}
{% tab title="Curl" %}

```bash
curl https://echo.sandbox.verygoodvault.com/post --cacert path/to/sandbox.pem \
  -x https://USiyQvWcT7wcpy8gvFb1GVmz:2b48a642-615a-4b3c-8db5-e02a88147174@tntsfeqzp4a.sandbox.verygoodproxy.com:8443 \
  -H "Content-type: application/json" \
  -d '{"account_number": "tok_sandbox_w8CBfH8vyYL2xWSmMWe3Ds"}'
```

{% endtab %}

{% tab title="Go" %}

```go
package main

import (
  "bytes"
  "encoding/json"
  "io/ioutil"
  "fmt"
  "net/http"
  "os"
  "crypto/tls"
  "crypto/x509"
)


type Payload struct {
  Account string `json:"account_number"`
}

func main() {
  // You can set the proxy as an HTTPS env variable proxyUrl and go will use by default:
  os.Setenv("HTTPS_PROXY", "https://USiyQvWcT7wcpy8gvFb1GVmz:2b48a642-615a-4b3c-8db5-e02a88147174@tntsfeqzp4a.sandbox.verygoodproxy.com:8443")

  data := Payload{
    Account: "tok_sandbox_w8CBfH8vyYL2xWSmMWe3Ds",
  }
  payloadBytes, err := json.Marshal(data)
  if err != nil {
    fmt.Println(err)
  }

  body := bytes.NewReader(payloadBytes)

  caCert, err := ioutil.ReadFile("path/to/sandbox.pem")
  if err != nil {
    fmt.Println(err)
  }
  caCertPool := x509.NewCertPool()
  caCertPool.AppendCertsFromPEM(caCert)

  client := &http.Client{
    Transport: &http.Transport{
      Proxy: http.ProxyFromEnvironment,
      TLSClientConfig: &tls.Config{
        RootCAs: caCertPool,
        InsecureSkipVerify: true,
      },
    },
  }

  req, err := http.NewRequest("POST", "https://echo.apps.verygood.systems/post", body)
  if err != nil {
    fmt.Println(err)
  }
  req.Header.Set("Content-Type", "application/json")

  resp, err := client.Do(req)
  if err != nil {
    fmt.Println(err)
  }

  defer resp.Body.Close()

  respB, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    fmt.Println(err)
  }
  fmt.Println(string(respB))
}
```

{% endtab %}

{% tab title="Java" %}

```java
package com.verygoodsecurity;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

public class OutboundIntegration {

  public static void main(String[] args) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
    tlsProxy();
  }

  private static void tlsProxy() throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
    final int proxyPort = {SECURE_PORT};
    CredentialsProvider credsProvider = new BasicCredentialsProvider();
    credsProvider.setCredentials(
        new AuthScope("tntsfeqzp4a.sandbox.verygoodproxy.com", proxyPort),
        new UsernamePasswordCredentials("USiyQvWcT7wcpy8gvFb1GVmz", "2b48a642-615a-4b3c-8db5-e02a88147174"));
    HttpHost proxy = new HttpHost("tntsfeqzp4a.sandbox.verygoodproxy.com", proxyPort, "https");
    HttpHost target = new HttpHost(new URL("https://echo.apps.verygood.systems").getHost(), 443, "https");

    CloseableHttpClient httpclient = HttpClients.custom()
        .setSSLSocketFactory(getSslConnectionSocketFactory())
        .setDefaultCredentialsProvider(credsProvider).build();

    try {

      RequestConfig config = RequestConfig.custom()
          .setProxy(proxy)
          .build();
      HttpPost httpPost = getRequest(config);


      CloseableHttpResponse response = httpclient.execute(target, httpPost);
      try {
        System.out.println("status code=" + response.getStatusLine());
        System.out.println("response=" + EntityUtils.toString(response.getEntity()));
      } finally {
        response.close();
      }
    } catch (ClientProtocolException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      httpclient.close();
    }
  }

  private static HttpPost getRequest(RequestConfig config) throws UnsupportedEncodingException {
    HttpPost httpPost = new HttpPost("/post");
    HttpEntity requestEntity = new StringEntity("{"account_number":"{ALIAS}"}");
    httpPost.setHeader("Content-Type", "application/json");
    httpPost.setEntity(requestEntity);
    httpPost.setConfig(config);
    return httpPost;
  }

  private static SSLConnectionSocketFactory getSslConnectionSocketFactory() throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException {

    SSLContext sslcontext = SSLContexts.custom()
        .loadTrustMaterial(getKeystore(), null)
        .build();
    return new SSLConnectionSocketFactory(
        sslcontext,
        new String[] { "TLSv1.2" },
        null,
        SSLConnectionSocketFactory.getDefaultHostnameVerifier());

  }

  private static KeyStore getKeystore() throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException {
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    ks.load(null, "vgs".toCharArray());

    FileInputStream fis = new FileInputStream("path/to/sandbox.pem");
    X509Certificate vgsSelfSigned = (X509Certificate) CertificateFactory.getInstance("X.509")
        .generateCertificate(new BufferedInputStream(fis));
    ks.setCertificateEntry("VGS Self Signed Certificate", vgsSelfSigned);
    URL destinationURL = new URL("https://" + "tntsfeqzp4a.sandbox.verygoodproxy.com");
    HttpsURLConnection conn = (HttpsURLConnection) destinationURL.openConnection();
    conn.connect();
    Arrays.stream(conn.getServerCertificates()).forEach(certificate -> {
      try {
        ks.setCertificateEntry(String.valueOf(certificate.hashCode()), certificate);
      } catch (KeyStoreException e) {
        e.printStackTrace();
      }
    });
    return ks;
  }
}
```

{% endtab %}

{% tab title="Python" %}

```python
import json
import tempfile
import os

import requests # requires requests==2.26.0 and urllib3==1.26.7
from requests import utils

def send_post_request(url, proxy, payload, headers, ca):
    return requests.post(url, proxies={f'https': proxy},
                         data=json.dumps(payload),
                         headers=headers, verify=ca)


def vgs_proxy():
    payload = {'account_number': 'tok_sandbox_w8CBfH8vyYL2xWSmMWe3Ds'}
    path_to_lib_ca = utils.DEFAULT_CA_BUNDLE_PATH
    path_to_vgs_ca = 'path/to/sandbox.pem'
    with tempfile.NamedTemporaryFile() as ca_file:
        ca_file.write(read_file(path_to_vgs_ca))
        ca_file.write(str.encode(os.linesep))
        ca_file.write(read_file(path_to_lib_ca))
        read_file(ca_file.name)
        return send_post_request(
            url=f'https://echo.apps.verygood.systems/post',
            proxy=f'https://USiyQvWcT7wcpy8gvFb1GVmz:2b48a642-615a-4b3c-8db5-e02a88147174@tntsfeqzp4a.sandbox.verygoodproxy.com:8443',
            payload=payload,
            headers={
                'Content-type': 'application/json',
                'User-Agent': "requests-python"
            },
            ca=ca_file.name).content


def read_file(path):
    with open(path, mode='rb') as file:
        return file.read()


print(vgs_proxy())
```

{% endtab %}

{% tab title="Ruby" %}

{% endtab %}
{% endtabs %}

> For Spring-based Java applications, you can use our [vgs-proxy-spring](https://github.com/verygoodsecurity/vgs-proxy-spring) library.

**Example Use Case:** You need to send a customer’s Social Security number (SSN) to the Acme Background Check Service. You:

* have previously collected the social security number
* exchanged it for a VGS token to store in your database.

Now you should:

1. Create an outbound route in your VGS dashboard
2. Set Acme’s endpoint as the upstream host
3. Add a reveal filter in the request phase to replace the tokenized SSN with the real value
4. Add the route to your network as a forward proxy

The outbound/forward proxy directs traffic between your server (outbound), the VGS vault (where sensitive data is stored), and your third-party integrations, as illustrated by the image below.&#x20;

<figure><img src="/files/sXoxnFPhfCEHktkYl6sC" alt=""><figcaption></figcaption></figure>

Use this command for testing the setup to simulate your back end (using cURL)

\`simulate-backend-integration\`

### How to implement?

We have several examples of API Call specific outbound implementations [here](https://github.com/vgs-samples/vgs-proxy-examples).

\`forward-implementation-example\`

For many languages, setting the proxy as an environmental variable enables the outbound/forward proxy to be used at a framework or library level.

### HTTP Basic Authentication

This enables a password of your VGS vault, so that only your application can reveal and access sensitive data. You must provide the [username and password](/vault/http-proxy/outbound-connection/access-credentials.md) via the following URL format. `https://<USERNAME>:<PASSWORD>@<VAULT_ID>.<ENVIRONMENT>.verygoodproxy.com:8443`

***Note: Some backend languages require you to access this url by passing auth in a different manner.***

VGS outbound/forward proxy reveal operations require HTTP Basic Authentication using the [username and password](/vault/http-proxy/outbound-connection/access-credentials.md) provided in the VGS dashboard.

It is up to you to protect these credentials; treat them like an API key. Please refer [Basic Authentication](http://en.wikipedia.org/wiki/HTTP_Authentication) for more information.

### Tips on storing HTTP Basic Authentication Secrets Securely

* Do not embed secrets directly in code.
* Do not store secrets in files inside your application, including the application’s source tree.
* If you do accidentally commit secrets to version control, revoke it immediately and generate a new one.
* Ensure secrets do not appear in URLs or anywhere they can be captured in web server logs.
* Review your code carefully and ensure it doesn’t contain secrets or any other private information before publicly releasing it.
* Put the configuration file containing the secrets in the revision control ignore. This prevents committing them by mistake in the future.
* Limit the usage of secrets
* Restrict your secrets to be used by only the IP addresses, referrer URLs, and mobile apps that need them. Don't share your secrets with different applications. If more than one application uses the same API, register each application so you get a new set of secrets and update the secrets.
* Delete unneeded secrets.
* Update (Regenerate) your secrets periodically.

**References:**

* [Best practices for securely using Secrets](https://support.google.com/cloud/answer/6310037?hl=en)
* [REST Security Cheat Sheet - OWASP](https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html)

### Encrypted Communication

VGS supports encryption to protect communications between VGS and your web application. VGS supports the TLS cryptographic protocol. Support for anything less than TLS1.2 is officially deprecated.

For more information regarding TLS:

* [Upgrading your application](https://support.cloudways.com/en/articles/5121355-how-to-update-the-tls-version)
* [PCI Standards Blog: TLS1.2](https://blog.pcisecuritystandards.org/are-you-ready-for-30-june-2018-sayin-goodbye-to-ssl-early-tls)
* [PCI TLS1.2 Guidance](https://www.pcisecuritystandards.org/documents/Migrating-from-SSL-Early-TLS-Info-Supp-v1_1.pdf)

### Alternative Using Reverse Proxy

If your server making outbound requests is already behind a proxy, it can be cumbersome to add a second, chained proxy. You can instead set up a VGS reverse proxy between your server and external services. This is simpler to implement, and suitable for testing, development, and building proof of concepts.

To implement, follow these steps:

1. If you already have an inbound route configured (which you likely do in order to securely collect PII), create a custom hostname for this route. For this example, suppose your custom hostname is backgroundcheck.yourcompany.com
2. Create an inbound route in your VGS dashboard
3. Set Acme’s endpoint as the upstream host
4. Set the route to allow requests to your custom hostname
5. Add a reveal filter in the request phase to replace the tokenized SSN with the real value
6. Modify your back end code to send the background check request to the custom hostname.

The data flow now looks like this.&#x20;

<figure><img src="/files/vmlzdMcoUMFLB7pHjkR5" alt=""><figcaption></figcaption></figure>

To test the setup using cURL to simulate your back end, run this cURL command.

```
curl https://backgroundcheck.yourcompany.com/post -k \
  -x https://tntsfeqzp4a.sandbox.verygoodproxy.com \
  -X POST \
  -H "Content-type: application/json"  \
  -d '{"ssn": "$VGS_TOKEN"}'
```

If you need any help setting up outbound connections, please contact us on site chat or at <support@vgs.io>.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.verygoodsecurity.com/vault/http-proxy/outbound-connection.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
