> For the complete documentation index, see [llms.txt](https://docs.licensespring.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.licensespring.com/sdks/go-sdk/v2/handler.md).

# Handler

The SDK exposes two entry points:

* **LicenseHandler**: Use this when you are working with a single license.
* **LicenseBundleHandler**: Use this when you are working with a bundle that contains multiple licenses, (starting from v2.1.0).

Both handlers orchestrate activation and storage by composing the same core modules:

* **LicenseManager**: Handles license logic, requests, and validations.
* **Storage**: Persists license data (e.g., license files, guard files) securely.

## LicenseHandler

The **LicenseHandler** is the primary entry point for **single-license** workflows. It initializes and connects the core modules (LicenseManager + Storage) and provides a unified interface to activate, validate, and persist a single license.

We provide a single setup function, `SetupHandler`, which simplifies configuration and lets you use either API Key authentication or OAuth.

The `NewLicenseHandler` function is the primary way to set up the `LicenseHandler`. It initializes and connects the core modules.

```go
func NewLicenseHandler(
config LicenseHandlerConfig,
) (*LicenseHandler, error)
```

**config**: Required configuration fields such as API keys, product code, and license key.

### What It Returns <a href="#mvlws" id="mvlws"></a>

Calling `NewLicenseHandler` constructs and returns a fully functional `*LicenseHandler` with:

* A configured `LicenseManager`
* A configured `Storage` backend
* A unified interface to handle license activation, checking, and storage operations

## LicenseBundleHandler

The **LicenseBundleHandler** is the entry point for **bundle** workflows. A bundle represents **multiple licenses** managed together under one handler instance.

It composes:

* `LicenseBundleManager`
* Storage

Where a `LicenseBundleManager` includes an array modeling a **collection of licenses**.

```
func NewBundleHandler(
config BundleHandlerConfig,
) (*BundleHandler, error)
```

#### What It Returns

Calling `NewBundleHandler(...)` constructs and returns a fully functional `*BundleHandler` with:

* A configured `LicenseBundleManager`
* A configured `Storage` backend
* A unified interface to activate/sync a bundle and work with the **licenses included in that bundle.**

### Basic Setup

This section shows minimal setup with defaults for both handlers. These examples use:

* API key authentication (non-OAuth)
* Default Managers
* Default file-based storage with encryption using the shared key

#### Minimal Setup with Defaults (LicenseHandler)

```go
lic_mngr_config := license_manager.LicenseManagerBasicConfiguration{
    OAuth:       false,
    ApiKey:      "your-api-key",
    SharedKey:   "your-shared-key",
    ProductCode: "your-product-code",
    AuthData:    auth.FromKey("LICENSE-KEY"),
}

cfg := license_handler.LicenseHandlerConfig{
    lic_mngr_config,
}

lic_handler, err := license_handler.NewLicenseHandler(cfg)
if err != nil {
    log.Fatal(err)
}
```

#### Minimal Setup with Defaults (LicenseBundleHandler)

```go
bndle_mngr_config := bundle_handler.BundleHandlerConfig{
		ApiKey:       config_file.ApiKey,
		SharedKey:    config_file.SharedKey,
		ClientId:     config_file.ClientId,
		ClientSecret: config_file.ClientSecret,
		BundleCode:   bundleCode,
		AuthData:     auth.FromKey(productAuth.LicenseKey),
		OAuth:        useOAuth,
}

BundleHandler, err := bundle_handler.NewBundleHandler(bndle_mngr_config)
if err != nil {
    log.Fatal(err)
}
```

### Advanced Usage <a href="#zxl1y" id="zxl1y"></a>

#### Providing a Custom LicenseManager <a href="#q3ddv" id="q3ddv"></a>

A demonstration of using different configuration options is shown here on a `LicenseManager` instance. This can be applied to `LicenseBundleManager` as well.

```go
lm_config := license_manager.LicenseManagerBasicConfiguration{
				OAuth:             false,
				ApiKey:            "your-api-key",
				SharedKey:         "your-shared-key",
				ProductCode:       "your-product-code",
				AuthData:          auth.FromKey("LICENSE-KEY"),
			}

lic_mngr, _ := license_manager.NewLicenseManager(
    lm_config,
    license_manager.WithRestyVerbose(true),
    license_manager.WithHardwareId("ABC"),
)

cfg.Manager = lic_mngr

lic_handler, _ := license_handler.NewLicenseHandler(cfg)
```

### OAuth Setup <a href="#kcn4t" id="kcn4t"></a>

When using OAuth, you have two options:

**Manually create a License or Bundle Manager using OAuth** and inject it into the handler config

```go
lm_config := license_manager.LicenseManagerBasicConfiguration{
				OAuth:             true,
				ClientId:          "your-client-id",
				ClientSecret:      "your-client-secret",
				ProductCode:       "your-product-code",
				AuthData:          auth.FromKey("LICENSE-KEY"),
			}
			
lm, _ := license_manager.NewLicenseManager(
    lm_config,
)

cfg.Manager = lm

lh, _ := license_handler.NewLicenseHandler(cfg)
```

**Provide OAuth-related fields via configuration object**, allowing `NewLicenseHandler` or `NewBundleHandler` to construct the manager internally.

```go
cfg := license_handler.LicenseHandlerConfig{
    OAuth: true,
    ProductCode: "your-product-code",
    AuthData:    auth.FromKey("LICENSE-KEY"),
    ClientId:      "placeholder",
    ClientSecret:   "placeholder",
    CryptoProviderKey: "placeholder",
}

lh, err := license_handler.NewLicenseHandler(cfg)
if err != nil {
    log.Fatal(err)
}
```

### Manager Configuration Options

The SDK provides **LicenseManager** to manage a single license and **LicenseBundleManager** to manage a bundle of licenses.

Both managers are initialized from a “basic configuration” struct that contains your auth mode (API key or OAuth), credentials, and `AuthData`.

#### LicenseManager

Use `NewLicenseManager(...)` (or `NewLicenseManagerOAuth(...)`) with `LicenseManagerBasicConfiguration`:

```go
type LicenseManagerBasicConfiguration struct {
	OAuth           bool
	ClientId        string
	ClientSecret    string
	ApiKey          string
	SharedKey       string
	ProductCode     string
	BaseUrl         string
	ApiPrefix       string
	ServerPublicKey string

	AuthData auth.Auth
}
```

#### LicenseBundleManager (bundle containing multiple licenses)

Use `NewLicenseBundleManager(...)` with `LicenseBundleConfiguration`:

```go
type LicenseBundleConfiguration struct {
	OAuth           bool
	ClientId        string
	ClientSecret    string
	ApiKey          string
	SharedKey       string

	BundleCode      string
	BaseUrl         string
	ApiPrefix       string
	ServerPublicKey string

	AuthData auth.Auth
}
```

* `BaseUrl` and `ApiPrefix` allow overriding the default server endpoint.
* `ServerPublicKey` is used for signature verification (can be left as default).

### Available Options

Both managers support the same optional configuration functions to override defaults (hardware ID, grace period, logging, offline/air-gapped behavior, etc.):

```go
WithRestyLogger(restyLogger resty.Logger)
WithAirGapPublicKey(airgappublickey string)
WithGracePeriod(gracePeriod int)
WithSyncPeriod(syncPeriod int)
WithRestyVerbose(verbose bool)
WithVerifySignature(verifySig bool)
WithEnableGuardFile(enableGuardFile bool)
WithHardwareId(hardwareId string)
WithBaseURL(url string)
WithHardwareIdAlgo(algo int)
WithMachineId()
WithServerPublicKey(publickey string)
WithAppName(appName string)
WithAppVersion(appVersion string)
WithHWKeySerialAsHWID()
WithCryptoSigner(signer crypto.Signer)
WithDisableHWKEYVerify(disable bool)
WithHardwareKeyPIN(pin string)
```

These options can be passed as variadic arguments to:

* `NewLicenseManager(...)`&#x20;
* `NewLicenseBundleManager(...)`


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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.licensespring.com/sdks/go-sdk/v2/handler.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.
