Connect a Go application
Add call and result checks to a protected Go function, then enforce it deliberately.
The Go SDK adds AuthRail checks around a function your application already uses. It asks the local sidecar to check the requested call and returned result, then gives your application those decisions.
This guide connects one invoice reader in Observe. You will read its call and result decisions and find the request in AuthRail. Observe keeps the function running even when a rule would deny it, so start with a safe system.
You need Go 1.26 or newer, an application module and a running sidecar. Complete the dashboard setup and connection details first. Keep the organisation ID, deployment ID, reviewed Operation Version ID, adapter-token file and private-key file available to your application.
1. Add the SDK to your module
From your application's module directory, install the versioned Go module:
go get github.com/AuthRail/authrail-sdk-go@v0.1.1For a new application, create its directory and run go mod init with your
module path first. go get records the SDK version in go.mod and go.sum;
it does not start the sidecar or your application.
Build from source when contributing
git clone https://github.com/AuthRail/authrail-sdk-go.git
cd authrail-sdk-go
go build ./...The SDK repository describes its tests. A successful build exits without starting a service.
2. Connect to the sidecar
Use imports context, os, strings, and authrail "github.com/AuthRail/authrail-sdk-go" in the surrounding Go file. Inside your application's setup function:
privatePEM, err := os.ReadFile(config.ExecutorPrivateKeyFile)
if err != nil { return err }
privateKey, err := authrail.ParseExecutorPrivateKeyPEM(privatePEM)
if err != nil { return err }
adapterToken, err := os.ReadFile(config.AdapterTokenFile)
if err != nil { return err }
client, err := authrail.NewClient(authrail.Config{
SidecarURL: "http://127.0.0.1:7078",
OrganisationID: config.OrganisationID,
DeploymentID: config.DeploymentID,
AdapterToken: strings.TrimSpace(string(adapterToken)),
ExecutorPrivateKey: privateKey,
})
if err != nil { return err }config is your application-owned configuration. Its file paths refer to the private adapter-token and executor-private.pem prepared during setup. Never mount the private key into the sidecar or expose it to the agent.
Use the native sidecar if this program runs on your host, or follow the Docker application placement if it runs in Docker. The local URL must reach the sidecar beside this application.
3. Check an invoice read
Here the application has authenticated a staff session and resolved an invoice before calling its own invoice reader:
invoiceResult, checks, err := authrail.Observe(ctx, client, authrail.Operation{
VersionID: config.InvoiceReadOperationVersionID,
ActionKey: request.StableBusinessKey,
PrincipalID: session.StaffID,
SessionID: session.ID,
ResourceID: invoice.ID,
PrincipalSource: "application_session",
ResourceSource: "application_lookup",
}, map[string]any{"invoiceId": invoice.ID},
func(ctx context.Context) (map[string]any, error) {
return invoiceService.Read(ctx, invoice.ID)
})
if err != nil { return err }
observation := <-checksctx, config, request, session, invoice and invoiceService belong to your application. The reader returns a bounded JSON object matching the reviewed Operation's result contract; adapt the example to your actual types. An action without a target record leaves ResourceID empty and uses ResourceSource: "not_applicable".
invoiceResult and err come from your business function. The function runs even if a Rail would deny the request or the sidecar is missing. The checks finish separately. Inspect observation.CallError and ResultError before reading CallDecision and ResultDecision.
4. Read the decisions
With a healthy setup, both phase decisions are available and their outcomes follow the selected Rails. RecordingStatus == "retained" means AuthRail stored the check; "queued" means the sidecar saved it for later delivery. Open the deployment's Actions & decisions to review retained Actions and certificates.
Use one stable business ActionKey across retries of the same request. A different request needs a different key. A callback result and an allow decision are separate: neither independently proves that a provider completed an effect.
Next: require permission before the function runs
Once you have checked the Observe decisions and reviewed other access routes, use Enforce to stop the function unless permission is established. Read Observe and Enforce, human approvals and recovery before changing that boundary.
Switch this integration to Enforce
In the deployment's Overview → Review Enforce setup, resolve any missing
setup or call/result reports, confirm the protected boundary and select
Turn on Enforce. Replace the advisory wrapper with Enforce:
receipt, call, result, err := authrail.Enforce(ctx, client, operation,
refundRequest, func(ctx context.Context, checked RefundRequest,
execution authrail.ExecutionContext) (RefundReceipt, error) {
if err := ledger.SaveRecovery(ctx, execution); err != nil {
return RefundReceipt{}, err
}
return payments.Refund(ctx, checked, execution.ProviderIdempotencyKey)
})This refund example uses your own operation, input/output types, ledger and
payments service. The SDK requires a covered allow decision or valid approval
permit, saved by AuthRail, and a saved execution-start report before calling
the function. Use its checked input and provider idempotency key.
Save recovery context before calling the provider. A result check can withhold
receipt after an effect exists; it cannot undo that effect.
Save an approval wait and recover uncertain outcomes
Use errors.As from Go's errors package to get a pending approval:
var pending *authrail.ApprovalRequired
if errors.As(err, &pending) {
continuation, snapshotErr := pending.Continuation()
if snapshotErr != nil { return snapshotErr }
// Encrypt and save continuation with this authenticated business request.
}The continuation includes private input and context. Encrypt it and save it with the original user, organisation, deployment and Action. Never accept a replacement continuation from an agent.
After approval, ResumeApprovalFrom[Input, Output] resumes the saved call. If a
permit claim response was lost, RecoverApprovalFrom reads the existing permit.
Both still require a saved execution start before an effect.
On OutcomeUnknownError, inspect Recovery, query the provider by the original
key, and call client.Reconcile only when the result is established. Leave
unresolved effects unknown. See recovery for the complete flow.
The SDK README covers complete
signatures, source facts, Guard handlers and discovery. From the SDK checkout,
go build ./... compiles it and go test ./... runs its source checks. Neither
starts the sidecar or establishes coverage of your application's other routes.
The Runtime walkthrough shows a connected application and the decisions it retained in AuthRail.