Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.authforge.cc/llms.txt

Use this file to discover all available pages before exploring further.

Requirements

  • Go 1.21 or later
  • No external dependencies (standard library only)

Installation

The module path is github.com/AuthForgeCC/authforge-go. Add a released version (pin a v1.x.y tag you rely on):
go get github.com/AuthForgeCC/authforge-go@v1.0.1
Imports always use github.com/AuthForgeCC/authforge-go. Run go mod tidy after editing go.mod.
module example.com/myapp

go 1.21

require github.com/AuthForgeCC/authforge-go v0.0.0

replace github.com/AuthForgeCC/authforge-go => ../path/to/authforge-go
Point replace at a directory that contains the SDK’s go.mod, then run go mod tidy.

Quick start

package main

import (
	"errors"
	"fmt"
	"os"

	"github.com/AuthForgeCC/authforge-go"
)

func main() {
	client, err := authforge.New(authforge.Config{
		AppID:         "YOUR_APP_ID",
		AppSecret:     "YOUR_APP_SECRET",
		PublicKey:     "YOUR_PUBLIC_KEY",
		HeartbeatMode: "server",
		OnFailure: func(errMsg string) {
			fmt.Fprintf(os.Stderr, "Auth failed: %s\n", errMsg)
			os.Exit(1)
		},
	})
	if err != nil {
		panic(err)
	}

	result, err := client.Login("XXXX-XXXX-XXXX-XXXX")
	if err != nil {
		switch {
		case errors.Is(err, authforge.ErrInvalidKey):
			fmt.Fprintln(os.Stderr, "Invalid license key.")
		default:
			fmt.Fprintf(os.Stderr, "Login failed: %v\n", err)
		}
		os.Exit(1)
	}

	fmt.Printf("Authenticated! Expires: %d\n", result.ExpiresIn)
	select {}
}

Config reference

client, err := authforge.New(authforge.Config{
	AppID:             "YOUR_APP_ID",              // Required
	AppSecret:         "YOUR_APP_SECRET",          // Required
	PublicKey:         "YOUR_PUBLIC_KEY",          // Required - Ed25519 public key from your AuthForge dashboard (base64)
	HeartbeatMode:     "server",                   // Required: "server" or "local"
	HeartbeatInterval: 15 * time.Minute,           // Optional (any value ≥ 1s)
	APIBaseURL:        "https://auth.authforge.cc",// Optional
	OnFailure:         nil,                        // Optional: func(error string)
	RequestTimeout:    15 * time.Second,           // Optional
	SessionTTL:        0,                          // Optional: time.Duration. 0 = server default (24h). Clamped to [1h, 7d].
	HWIDOverride:      "",                         // Optional: custom identity (for example "tg:123456789")
})

SessionTTL

Requested lifetime of the session token returned by /auth/validate. Leave at 0 to accept the server default (24 hours). The server clamps the final value to [1h, 7d]. The requested TTL is preserved across heartbeat refreshes, so long-lived apps using LOCAL mode can extend their offline window up to 7 days.

Billing

  • Each successful Login() or ValidateLicense() costs 1 credit (one /auth/validate debit).
  • Heartbeats cost 1 credit per 10 successful calls (billed on every 10th heartbeat). Any HeartbeatInterval ≥ 1s is economically safe.
  • Revocations take effect on the next heartbeat regardless of interval.

Validate license (no heartbeat)

ValidateLicense performs the same /auth/validate request and signature verification as Login, but does not persist session fields on the client, start the heartbeat goroutine, or invoke OnFailure for validate failures (network errors still return an error; repeated network failure does not call OnFailure when using ValidateLicense). The SDK recognizes AUTHFORGE_SDK_TEST_NONCE for integration tests only; never set it in production (it pins the validate nonce).

Methods reference

result, err := client.Login(licenseKey)
result, err = client.ValidateLicense(licenseKey) // same validate + signatures, no heartbeat / session persistence
client.Logout()
ok := client.IsAuthenticated()
session := client.SessionData()
appVars := client.AppVariables()
licenseVars := client.LicenseVariables()
Login and ValidateLicense return a LoginResult with:
  • SessionToken
  • ExpiresIn
  • AppVariables
  • LicenseVariables
  • RequestID

Error handling

The Go SDK exposes sentinel errors so you can branch with errors.Is:
if err != nil {
	switch {
	case errors.Is(err, authforge.ErrInvalidApp):
		// invalid app credentials
	case errors.Is(err, authforge.ErrInvalidKey):
		// invalid key
	case errors.Is(err, authforge.ErrExpired):
		// license expired
	case errors.Is(err, authforge.ErrRevoked):
		// license revoked
	case errors.Is(err, authforge.ErrHwidMismatch):
		// HWID slots full
	case errors.Is(err, authforge.ErrNoCredits):
		// no credits
	case errors.Is(err, authforge.ErrBlocked):
		// blocked
	case errors.Is(err, authforge.ErrRateLimited):
		// rate limited (validate only)
	case errors.Is(err, authforge.ErrReplayDetected):
		// replay detected (validate only)
	case errors.Is(err, authforge.ErrSignatureMismatch):
		// signature verification failed
	default:
		// transport or unexpected error
	}
}

Heartbeat modes

// SERVER mode
client, _ := authforge.New(authforge.Config{
	AppID:         "...",
	AppSecret:     "...",
	PublicKey:     "YOUR_PUBLIC_KEY",
	HeartbeatMode: "server",
})

// LOCAL mode
client, _ := authforge.New(authforge.Config{
	AppID:         "...",
	AppSecret:     "...",
	PublicKey:     "YOUR_PUBLIC_KEY",
	HeartbeatMode: "local",
})
See Heartbeat Modes for a detailed comparison.

GitHub

Source, releases, and issues: AuthForgeCC/authforge-go.