> This page is for Applications Protection.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.humansecurity.com/llms.txt.

# Installation

## Installing the Go Enforcer

The Go Enforcer is used as a middleware inside a Go web application.

### 1. Import the HUMAN Go Package.

> **GitHub Repository Access**
>
> If you do not have access the Go SDK GitHub Repository, please reach out to our Customer Support team.

To install the HUMAN Go Enforcer package, run the following command from within your Go project.

```sh
go get github.com/perimeterx/perimeterx-go-sdk/perimeterx
```

### 2. Implement the Runtime interface.

The HUMAN Go Enforcer package requires you to implement a `Runtime` interface, which the Enforcer uses to perform HTTP requests, log messages, and obtain metadata about the server.

```go
type Runtime interface {
    PerformSyncRequest(request *http.Request, timeout int) (*http.Response, error)
    PerformAsyncRequest(request *http.Request, timeout int)
    Log(message string)
    GetOS() string
    GetHostName() string
}
```

* **PerformSyncRequest** - Performs a synchronous HTTP request by sending the `*http.Request` argument and returning an `*http.Response`. If the provided `timeout` (in milliseconds) is reached before the `*http.Response` can be returned, then an error should be returned instead.
* **PerformAsyncRequest** - Performs an asynchronous request. The simplest way to implement this function is to call `PerformSyncRequest` from within a new goroutine.
* **Log** - Logs the provided `message` argument.
* **GetOS** - Returns the Operating System name as a string.
* **GetHostName** - Returns the host name as a string.

> **Removed GetConfig() Function**
>
> In previous versions of the HUMAN Go Enforcer, the `Runtime` interface required the implementation of a `GetConfig()` function that returned a `PxConfig` struct. This function is no longer necessary and will not be used.

The `ExampleRuntime` struct below implements the `perimeterx.Runtime` interface using a single `http.Client`. However, you can implement this with a `sync.Pool` of `http.Client` structs as well.

```go
// initialize http client
var client = &http.Client{
    Transport: &http.Transport{
        MaxIdleConnsPerHost:   10,
        ResponseHeaderTimeout: 60 * time.Second,
    }
}

// declare ExampleRuntime type
type ExampleRuntime struct {}

// implement PerformSyncRequest using http client
func (runtime *ExampleRuntime) PerformSyncRequest(req *http.Request, timeout int) (*http.Response, error) {
    client.Timeout = time.Duration(timeout) * time.Millisecond
    return client.Do(req)
}

// implement PerformAsyncRequest by invoking PerformSyncRequest in new goroutine
func (runtime *ExampleRuntime) PerformAsyncRequest(req *http.Request, timeout int) {
    go runtime.PerformSyncRequest(req, timeout)
}

// implement GetOS using goruntime package
func (runtime *ExampleRuntime) GetOS() string {
    return goruntime.GOOS
}

// implement GetHostName using os package
func (runtime *ExampleRuntime) GetHostName() string {
    osName, _ := os.Hostname()
    return osName
}

// implement Log using fmt package
func (runtime *ExampleRuntime) Log(message string) {
    fmt.Print(message)
}
```

### 3. Build the HUMAN configuration.

In order to initialize the enforcer, you must first create a `PxConfig` struct instance. There are three ways of doing this.

> **All possible configuration key names and value types are listed in the Configuration section of the documentation.**

**Directly**

The first way to do this is to use the `BuildPXConfig()` function. This function accepts a `map[string]interface{}` argument representing the configuration, and returns a pointer to a `PxConfig` struct (or an `error` if something went wrong).

```go
// build the configuration from map
pxConfig, err := perimterx.BuildPXConfig(map[string]interface{}{
    "px_app_id":        "<APP_ID>",
    "px_auth_token":    "<AUTH_TOKEN>",
    "px_cookie_secret": "<COOKIE_SECRET">,
    // ...
})
```

**JSON File**

You may store your configuration in a JSON file and load it into a `PxConfig` struct using the `GetPxConfigFromJson()` function. This function accepts a string representing the path to the JSON file, and returns a pointer to a `PxConfig` struct (or an `error` if something went wrong).

```go
// build the configuration from json
pxConfig, err := perimeterx.GetPxConfigFromJson("/path/to/enforcer_config.json")
```

The minimum JSON file should look like this:

```json
// enforcer_config.json
{
    "px_app_id": "<APP_ID>",
    "px_auth_token": "<AUTH_TOKEN>",
    "px_cookie_secret": "<COOKIE_SECRET>",
    // ...
}
```

**Builder**

You may call `NewPXConfigBuilder()` to initialize a `PXConfigBuilder` struct, which has setters for all possible configuration values. Once all the desired configurations have been set, call the `Build()` function to receive a pointer to a `PxConfig` struct.

```go
// build the configuration with builder
pxConfig := perimeterx.NewPXConfigBuilder(map[string]interface{}{
        // must initialize with the required configurations only
        "px_app_id":        "<APP_ID>",
        "px_auth_token":    "<AUTH_TOKEN>",
        "px_cookie_secret": "<COOKIE_SECRET">,
    })
    .SetModuleMode("active_blocking")
    // ...
    .Build()
```

### 4. Integrate the enforcer by adding a middleware.

**Using the Default HUMAN Security Middleware**

For an out-of-the-box middleware function, simply call the `CreateDefaultHumanSecurityMiddleware` function and pass in the `PxConfig` struct and `Runtime` implementation.

```go
func main() {
    // build the configuration
    pxConfig, err := perimterx.BuildPXConfig(map[string]interface{}{
        "px_app_id":        "<APP_ID>",
        "px_auth_token":    "<AUTH_TOKEN>",
        "px_cookie_secret": "<COOKIE_SECRET">,
        // ...
    })
    if err != nil {
        fmt.Printf("failed to initialize enforcer configuration: %s", err)
        return
    }

    // initialize the runtime
    runtime := &ExampleRuntime{}

    // create the HUMAN enforcement middleware
    defaultMiddleware := perimeterx.CreateDefaultHumanSecurityMiddleware(pxConfig, runtime)

    // use the HUMAN enforcement middleware to wrap HTTP handler functions
    http.Handle("/", defaultMiddleware(http.FileServer(http.Dir("./static"))))
    // ...

    // serve
    http.ListenAndServe(":3000", nil)
}
```

**Creating a Customized Middleware**

For a more customized solution, initialize a `HumanSecurityEnforcer` struct and use it in your custom middleware function.

The recommended usage is to:

* create the `HumanSecurityEnforcer` struct once (not on every middleware invocation) by calling `NewHumanSecurityEnforcer()`
* Call the `Enforce()` function as soon as possible in the request handler and interpret the returned values
* Set the PXHD cookie on the response if necessary by calling `perimeterx.ShouldSetPxhd()` and `perimeterx.GetPxhdCookie()`
* If `Enforce()` returned a non-`nil` response, transfer it to the `http.ResponseWriter` and exit without invoking the provided `handler`
* If `Enforce()` returned a `nil` response, invoke the provided `handler`

```go
// define global variables
var enforcer *perimeterx.HumanSecurityEnforcer
var runtime perimeterx.Runtime

func main() {
    // build the configuration
    pxConfig, err := perimterx.BuildPXConfig(map[string]interface{}{
        "px_app_id":        "<APP_ID>",
        "px_auth_token":    "<AUTH_TOKEN>",
        "px_cookie_secret": "<COOKIE_SECRET">,
        // ...
    })
    if err != nil {
        fmt.Printf("failed to initialize enforcer configuration: %s", err)
        return
    }

    // initialize the runtime
    runtime = &ExampleRuntime{}

    // initialize the enforcer
    enforcer = NewHumanSecurityEnforcer(pxConfig, runtime)

    // use the HUMAN enforcement middleware to wrap HTTP handler functions
    http.Handle("/", customMiddleware(http.FileServer(http.Dir("./static"))))
    // ...

    // serve
    http.ListenAndServe(":3000", nil)
}

// define custom middleware that accepts an HTTP handler function
func customMiddleware(handler http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        // call the global enforcer's enforcement function
        response, context, err := enforcer.Enforce(r, runtime)

        // set pxhd cookie if needed
        if perimeterx.ShouldSetPxhd(context) {
            pxhdCookie := perimeterx.GetPxhdCookie(context)
            http.SetCookie(w, &pxhdCookie)
        }

        // if there was an error, log it
        if err != nil {
            runtime.Log(fmt.Sprintf("enforcer error: %s", err))
        }

        if response != nil {
            // if the response exists...
            // write the response status code, headers, and body with the http.ResponseWriter
            for key, value := range response.Header {
                w.Header().Set(key, value[0])
            }
            var body, _ = io.ReadAll(response.Body)
            w.WriteHeader(response.StatusCode)
            w.Write(body)
        } else {
            // if the response does not exist...
            // invoke the provided handler
            handler(w, r)
        }
    }
}
```

> **Using Credential Intelligence?**
>
> The Credential Intelligence product also requires the sending of an `additional_s2s` activity, which indicates whether the login attempt was successful. To properly determine whether the login attempt was successful and send the `additional_s2s` activity, use the `perimeterx.NewResponseWriterWrapper()` and `PostEnforce()` functions. See code sample below.

```go
func customMiddleware(handler http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {

        // enforcement, error handling, setting pxhd, etc...

        if response != nil {
            // ...
        } else {
            // if the response does not exist...
            // create a new response writer wrapper to store the response body
            responseWriterWrapper := perimeterx.NewResponseWriterWrapper(w)

            // defer an invocation to send the additional_s2s activity
            defer enforcer.PostEnforce(responseWriterWrapper, context, runtime)

            // invoke the provided handler with the response writer wrapper
            handler(responseWriterWrapper, r)
        }
    }
```