Skip to content

Go Authentication Examples

This page provides practical examples of how to use authentication with the CounterAPI Go client.

Note: Authentication is required for the V2 API, which is now the only available CounterAPI version. The legacy V1 API did not support authentication and was deprecated on August 7, 2026.

Prerequisites

Before you can use authentication, you need to:

  1. Create an account on CounterAPI
  2. Create a workspace
  3. Generate an access token

For detailed instructions on these steps, see the Authentication guide.

Basic Authentication

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/counterapi/api/pkg/client"
)

func main() {
    // Create an authenticated client
    counter, err := client.New(
        client.WithWorkspace("your-workspace-name"),
        client.WithAccessToken("your-access-token"), // The token you generated on counterapi.dev
    )
    if err != nil {
        log.Fatalf("Failed to create client: %v", err)
    }

    // Use the authenticated client
    ctx := context.Background()
    result, err := counter.Get(ctx, "secure-counter")
    if err != nil {
        log.Fatalf("Failed to get counter: %v", err)
    }

    fmt.Printf("Counter value: %d\n", result.Value)
}

Using Environment Variables

It's best practice to store your authentication tokens in environment variables:

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/counterapi/api/pkg/client"
)

func main() {
    // Using environment variables in Go
    counter, err := client.New(
        client.WithWorkspace(os.Getenv("COUNTER_WORKSPACE")),
        client.WithAccessToken(os.Getenv("COUNTER_API_TOKEN")),
    )
    if err != nil {
        log.Fatalf("Failed to create client: %v", err)
    }

    ctx := context.Background()
    result, err := counter.Up(ctx, "api-call-counter")
    if err != nil {
        log.Fatalf("Failed to update counter: %v", err)
    }

    fmt.Printf("Updated count: %d\n", result.Value)
}

Authentication with Custom HTTP Client

You can use a custom HTTP client with your authenticated CounterAPI client:

package main

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "time"

    "github.com/counterapi/api/pkg/client"
)

func main() {
    // Create a custom HTTP client with specific timeout
    httpClient := &http.Client{
        Timeout: 5 * time.Second,
    }

    // Create an authenticated counter client with custom HTTP client
    counter, err := client.New(
        client.WithWorkspace("your-workspace-name"),
        client.WithAccessToken("your-access-token"),
        client.WithHTTPClient(httpClient),
    )
    if err != nil {
        log.Fatalf("Failed to create client: %v", err)
    }

    // Use the authenticated client
    ctx := context.Background()
    result, err := counter.Up(ctx, "secure-counter")
    if err != nil {
        log.Fatalf("Failed to update counter: %v", err)
    }

    fmt.Printf("Counter value: %d\n", result.Value)
}

With Error Handling

More comprehensive error handling for authentication issues:

package main

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "os"

    "github.com/counterapi/api/pkg/client"
)

func main() {
    // Create an authenticated client
    counter, err := client.New(
        client.WithWorkspace(os.Getenv("COUNTER_WORKSPACE")),
        client.WithAccessToken(os.Getenv("COUNTER_API_TOKEN")),
    )
    if err != nil {
        log.Fatalf("Failed to create client: %v", err)
    }

    ctx := context.Background()
    result, err := counter.Get(ctx, "secure-counter")
    if err != nil {
        // Handle different types of authentication errors
        var httpErr *client.HTTPError
        if errors.As(err, &httpErr) {
            switch httpErr.StatusCode {
            case http.StatusUnauthorized:
                log.Fatalf("Authentication failed: Invalid token")
            case http.StatusForbidden:
                log.Fatalf("Permission denied: Token lacks required permissions")
            case http.StatusNotFound:
                log.Fatalf("Workspace or counter not found")
            default:
                log.Fatalf("HTTP error: %v", err)
            }
        } else {
            log.Fatalf("Error: %v", err)
        }
    }

    fmt.Printf("Counter value: %d\n", result.Value)
}

With HTTP Web Server

Here's how to implement authenticated counter updates in a Go HTTP server:

package main

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "os"
    "strings"

    "github.com/counterapi/api/pkg/client"
)

func main() {
    // Create an authenticated counter client
    counter, err := client.New(
        client.WithWorkspace(os.Getenv("COUNTER_WORKSPACE")),
        client.WithAccessToken(os.Getenv("COUNTER_API_TOKEN")),
    )
    if err != nil {
        log.Fatalf("Failed to create client: %v", err)
    }

    // Create a middleware to track endpoint usage
    trackEndpoint := func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            // Format endpoint name for counter
            endpoint := strings.ReplaceAll(r.URL.Path, "/", "-")
            if endpoint == "" || endpoint == "-" {
                endpoint = "root"
            }
            counterName := fmt.Sprintf("endpoint%s", endpoint)

            // Update counter in a goroutine to avoid blocking
            go func() {
                ctx := context.Background()
                _, err := counter.Up(ctx, counterName)
                if err != nil {
                    log.Printf("Failed to update counter for %s: %v", endpoint, err)
                }
            }()

            next.ServeHTTP(w, r)
        })
    }

    // Define a simple handler
    helloHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, authenticated world!")
    })

    // Apply middleware and start server
    http.Handle("/", trackEndpoint(helloHandler))
    port := "8080"
    if p := os.Getenv("PORT"); p != "" {
        port = p
    }

    fmt.Printf("Server listening on port %s...\n", port)
    log.Fatal(http.ListenAndServe(":"+port, nil))
}