Skip to content

Webhooks

Authara can notify your application about user and organization lifecycle events via webhooks.

This allows your application to stay in sync with Authara without polling or tightly coupling to internal state.


Overview

When configured, Authara stores webhook events in its database and a background worker pool sends HTTP POST requests to your webhook endpoint.

Supported events:

  • user.created
  • user.updated
  • user.deleted
  • organization.created
  • organization.updated
  • organization.deleted
  • organization.membership.created
  • organization.membership.updated
  • organization.membership.deleted
  • organization.invitation.created
  • organization.invitation.accepted
  • organization.invitation.revoked

Configuration

Webhooks are configured via environment variables.

Required

AUTHARA_WEBHOOK_URL=https://app.example.com/webhooks/authara
AUTHARA_WEBHOOK_SECRET=your-secret

Optional

AUTHARA_WEBHOOK_ENABLED_EVENTS=user.created,user.deleted,organization.invitation.created
AUTHARA_WEBHOOK_TIMEOUT=5s

Variables

AUTHARA_WEBHOOK_URL

The endpoint that receives webhook events.

Must include scheme (http:// or https://).


AUTHARA_WEBHOOK_SECRET

Shared secret used to sign webhook requests.

Your application must verify incoming requests using this secret.


AUTHARA_WEBHOOK_ENABLED_EVENTS

Comma-separated list of events to send.

Example:

AUTHARA_WEBHOOK_ENABLED_EVENTS=user.created,user.deleted

Default behavior:

If unset, all supported events are sent.


AUTHARA_WEBHOOK_TIMEOUT

HTTP timeout for webhook delivery.

It must be shorter than AUTHARA_WEBHOOK_PROCESSING_STALE_AFTER.

Default:

5s

AUTHARA_WEBHOOK_WORKER_COUNT

Number of webhook events that can be delivered concurrently.

Default:

2

Queue reliability settings

Variable Default
AUTHARA_WEBHOOK_MAX_DELIVERY_ATTEMPTS 3
AUTHARA_WEBHOOK_PROCESSING_STALE_AFTER 2m
AUTHARA_WEBHOOK_STALE_REAPER_INTERVAL 1m
AUTHARA_WEBHOOK_DELIVERED_RETENTION 24h
AUTHARA_WEBHOOK_FAILED_RETENTION 720h
AUTHARA_WEBHOOK_CLEANUP_INTERVAL 1h
AUTHARA_WEBHOOK_MAINTENANCE_BATCH_SIZE 1000

Event Delivery

Authara sends webhook events as HTTP POST requests.

Request

POST /your-endpoint
Content-Type: application/json
X-Authara-Event: user.created
X-Authara-Delivery: evt_123
X-Authara-Signature: sha256=...

Body

{
  "id": "evt_123",
  "type": "user.created",
  "created_at": "2026-03-20T12:00:00Z",
  "data": {
    "user_id": "uuid"
  }
}

Organization events include the organization id, name, kind, and creator when available. Created-membership events also include whether the membership was created with the organization, the source invitation id when applicable, and the invitation's opaque metadata. Invitation events include the invitation id, organization id, invited email, Authara role, and opaque application metadata.


Signature Verification

Each request is signed using HMAC-SHA256.

Header:

X-Authara-Signature: sha256=<hex>

Computed as:

HMAC_SHA256(secret, request_body)

Example (Go)

func verifySignature(secret string, body []byte, header string) bool {
    expected := webhook.Sign(secret, body)
    return hmac.Equal([]byte(expected), []byte(header))
}

Always verify signatures before processing webhook events.


Delivery Semantics

  • The event type and complete JSON payload are inserted into webhook_events in the same transaction as the action
  • Application requests never wait for webhook HTTP delivery
  • Workers claim the oldest pending events using FOR UPDATE SKIP LOCKED
  • Workers drain available work immediately and poll again after one second only when the queue is empty
  • Delivery is best-effort
  • Network errors, HTTP 429, and HTTP 5xx responses are retried after 30 seconds, then every two minutes up to AUTHARA_WEBHOOK_MAX_DELIVERY_ATTEMPTS
  • Other HTTP 4xx responses fail immediately
  • A reaper restores stale processing events according to the configured interval and threshold
  • Cleanup applies the configured delivered and failed retention periods in configured batch sizes

This means:

  • committed actions have a durable webhook event even if the endpoint is down
  • the same delivery ID can be sent more than once after stale-job recovery
  • your handler should be idempotent

Idempotency

Each event includes a unique ID:

"id": "evt_123"

Your application should:

  • track processed event IDs
  • ignore duplicates

Example Handler

http.HandleFunc("/webhooks/authara", func(w http.ResponseWriter, r *http.Request) {
    defer r.Body.Close()

    body, err := io.ReadAll(r.Body)
    if err != nil {
        http.Error(w, "invalid body", http.StatusBadRequest)
        return
    }

    signature := r.Header.Get("X-Authara-Signature")

    if !verifySignature(os.Getenv("AUTHARA_WEBHOOK_SECRET"), body, signature) {
        http.Error(w, "invalid signature", http.StatusUnauthorized)
        return
    }

    var evt struct {
        ID    string `json:"id"`
        Event string `json:"type"`
        Data  struct {
            UserID string `json:"user_id"`
        } `json:"data"`
    }

    if err := json.Unmarshal(body, &evt); err != nil {
        http.Error(w, "invalid payload", http.StatusBadRequest)
        return
    }

    switch evt.Event {
    case "user.created":
        // handle user creation
    case "user.updated":
        // handle user updates
    case "user.deleted":
        // handle user deletion
    case "organization.created":
        // project organization creation
    case "organization.updated":
        // update organization projection
    case "organization.deleted":
        // delete organization projection
    case "organization.membership.created":
        // project organization membership
    case "organization.membership.updated":
        // update organization membership
    case "organization.membership.deleted":
        // delete organization membership
    case "organization.invitation.created":
        // track pending invitation
    case "organization.invitation.accepted":
        // mark invitation accepted
    case "organization.invitation.revoked":
        // mark invitation revoked
    }

    w.WriteHeader(http.StatusNoContent)
})

Security

  • Always verify webhook signatures
  • Use HTTPS in production
  • Treat webhook data as untrusted input

Summary

Webhooks allow Authara to notify your application about important events.

They are:

  • simple to configure
  • easy to integrate
  • essential for keeping your application in sync