For AI agents: A markdown version of this page is available at https://docs.datadoghq.com/security/application_security/setup/go/sdk.md. A documentation index is available at /llms.txt.
This product is not supported for your selected Datadog site. ().

App and API Protection is in Preview on Datadog Government site US1-FED.

If you need flexibility and features beyond those available when instrumenting your application automatically using Orchestrion, Datadog provides an App and API Protection API located at github.com/DataDog/dd-trace-go/v2/appsec. This API improves flexibility and offers additional features.

Error event handling

The API error type events.BlockingSecurityEvent is returned when a blocking event occurs, such blocking a user, IP, or request.

Do not write any response to the client when you receive a BlockingSecurityEvent error. A response could potentially send sensitive information to an attacker. To safely detect this type of error, use the helper function events.IsSecurityError.

When a BlockingSecurityEvent is returned, the SDK automatically sends a blocking response for you, typically an HTTP 403 Forbidden.

Customizing this behavior is possible. See the Customize response to blocked requests section.

HTTP body monitoring

By default, a lot of Go HTTP Frameworks are not high level enough to provide parsed HTTP request and response bodies. Consequently, the App and API Protection SDK provides a way to monitor the HTTP request and response bodies manually:

These functions automatically block the current request if the Protection feature is enabled, and return a BlockingSecurityEvent error.

User tracking

User login events can be tracked and blocked using the track and block login requests feature from these functions:

These functions automatically block the current request if the Protection feature is enabled, and return a BlockingSecurityEvent error.

Custom event tracking

You can track Business logic events like user login success/failure using the appsec.TrackCustomEvent function. This function sets custom event data as service entry span tags, which triggers backend event monitoring, and can ultimately block IP addresses and/or associated user IDs.

Example

Here’s a concise example showing how to integrate the App and API Protection SDK into a standard net/http web application:

main.go

package main

import (
	"encoding/json"
	"log"
	"net/http"
	"strings"

	"github.com/DataDog/dd-trace-go/v2/appsec"
	"github.com/DataDog/dd-trace-go/v2/appsec/events"
	"github.com/DataDog/dd-trace-go/v2/contrib/net/http/v2"
	"github.com/DataDog/dd-trace-go/v2/ddtrace/tracer"
)

type LoginRequest struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

type User struct {
	Name     string `json:"name"`
	Username string `json:"username"`
	Email    string `json:"email"`
	password string
}

var users = []User{
	{
		Name: "John Doe",
		Username: "realjoe",
		Email: "john@gmail.com",
		password: "not-my-birthday",
	}
}

func main() {
	tracer.Start(tracer.WithService("my-web-app"), tracer.WithAppsecEnabled(true))
	defer tracer.Stop()

	mux := httptrace.NewServeMux()
	mux.HandleFunc("/login", loginHandler)
	mux.HandleFunc("/profile", authMiddleware(profileHandler))

	log.Fatal(http.ListenAndServe(":8080", mux))
}

func loginHandler(w http.ResponseWriter, r *http.Request) {
	var req LoginRequest
	json.NewDecoder(r.Body).Decode(&req)

	// Monitor parsed request body
	if err := appsec.MonitorParsedHTTPBody(r.Context(), req); err != nil {
		if events.IsSecurityError(err) {
			return // AppSec handles the blocking response
		}
	}

	for _, user := range users {
		if req.Username == user.Username && req.Password == user.Password {
			metadata := map[string]string{"login_method": "password"}
			if err := appsec.TrackUserLoginSuccess(r.Context(), req.Username, "user123", metadata); err != nil && events.IsSecurityError(err) {
				return // User is blocked
			}

			response := map[string]string{"token": "<token_created>", "status": "success"}

			// Monitor response body
			appsec.MonitorHTTPResponseBody(r.Context(), response)

			w.Header().Set("Content-Type", "application/json")
			json.NewEncoder(w).Encode(response)
			return
		}
	}

	// Track failed login
	appsec.TrackUserLoginFailure(r.Context(), req.Username, true, nil)
	http.Error(w, "Invalid credentials", http.StatusUnauthorized)
}

func authMiddleware(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		user := "<username>" // Do real authentication here

		// Set user context on all authenticated requests
		if err := appsec.SetUser(r.Context(), user); err != nil && events.IsSecurityError(err) {
			return // User is blocked
		}

		next.ServeHTTP(w, r)
	}
}

func profileHandler(w http.ResponseWriter, r *http.Request) {
	// Track access to sensitive data
	appsec.TrackCustomEvent(r.Context(), "profile.access", map[string]string{
		"data_type": "personal_info",
	})

	userAsked := r.URL.Query().Get("user")
	user := users[0] // Search for the user

	// Monitor response body
	appsec.MonitorHTTPResponseBody(r.Context(), user);
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(user)
}

This example demonstrates:

  • Body Monitoring: MonitorParsedHTTPBody and MonitorHTTPResponseBody for request/response security
  • User Tracking: TrackUserLoginSuccess/TrackUserLoginFailure for login events, SetUser for authentication
  • Custom Events: TrackCustomEvent for business logic monitoring
  • Error Handling: Proper BlockingSecurityEvent handling with IsSecurityError

Key points:

  • Always check IsSecurityError(err) and return without writing responses when blocked
  • Use SetUser on authenticated requests to enable user blocking capabilities
  • Track important business events that could indicate suspicious activity

Further Reading