Authsome delivers event notifications to your own HTTP endpoints via webhooks. Every significant event -- user creation, sign-in attempts, MFA enrollment, organization changes, environment lifecycle -- fires a webhook. You can configure multiple endpoints and subscribe each one to different event types.
The Webhook model01
import "github.com/xraph/authsome/webhook"
type Webhook struct {
ID id.ID `json:"id"` // awhk_ prefix
AppID string `json:"app_id"`
EnvID string `json:"env_id"`
OrgID *id.ID `json:"org_id,omitempty"` // nil for app-level webhooks
Name string `json:"name"`
URL string `json:"url"`
Secret string `json:"-"` // HMAC signing secret -- never exposed after creation
SecretHash string `json:"-"` // stored hash
Events []string `json:"events"` // subscribed event types
IsActive bool `json:"is_active"`
Headers map[string]string `json:"headers,omitempty"` // custom HTTP headers
MaxRetries int `json:"max_retries"` // 0-5, default 3
TimeoutMs int `json:"timeout_ms"` // delivery timeout, default 5000
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}All event types02
Authsome emits 31 event types grouped by category:
User events
| Event | Description |
user.created | A new user account was created |
user.updated | User profile information was updated |
user.deleted | A user account was permanently deleted |
Session events
| Event | Description |
session.created | A new session was created (sign-in) |
session.revoked | A session was revoked (sign-out or forced termination) |
Auth events
| Event | Description |
auth.signin | Successful sign-in |
auth.signin.failed | Failed sign-in attempt |
auth.signout | User signed out |
auth.password.reset | Password was reset |
auth.mfa.enabled | MFA was enabled on the account |
auth.mfa.enrolled | A specific MFA method was enrolled (TOTP, SMS, etc.) |
auth.mfa.verified | An MFA challenge was successfully verified |
auth.mfa.challenged | An MFA challenge was initiated |
auth.mfa.disabled | MFA was disabled on the account |
Passkey events
| Event | Description |
passkey.registered | A new passkey (WebAuthn credential) was registered |
passkey.authenticated | Authentication via passkey succeeded |
passkey.deleted | A passkey credential was removed |
Social events
| Event | Description |
social.signin | Sign-in via a social OAuth provider (Google, GitHub, etc.) |
social.signup | New account created via social OAuth |
SSO events
| Event | Description |
sso.signin | Sign-in via enterprise SSO (OIDC or SAML) |
sso.signup | New account created via enterprise SSO |
Organization events
| Event | Description |
org.created | A new organization was created |
org.updated | Organization details were updated |
org.member.invited | A user was invited to the organization |
org.member.joined | An invited user accepted and joined |
org.member.removed | A member was removed from the organization |
org.member.role_changed | A member's role was changed |
Environment events
| Event | Description |
environment.created | A new environment was created |
environment.updated | Environment settings were updated |
environment.deleted | An environment was deleted |
environment.cloned | An environment was cloned from another |
API key events
| Event | Description |
apikey.created | A new API key was created |
apikey.revoked | An API key was revoked |
Consent events
| Event | Description |
consent.granted | A user granted consent |
consent.revoked | A user revoked a previously granted consent |
Creating a webhook03
import "github.com/xraph/authsome/webhook"
result, err := auth.Webhooks().Create(ctx, &webhook.CreateInput{
Name: "My Backend Notifications",
URL: "https://api.myapp.com/authsome/events",
Events: []string{
"user.created",
"user.deleted",
"auth.signin",
"auth.signin.failed",
"session.revoked",
},
Headers: map[string]string{
"X-Source": "authsome",
},
MaxRetries: 3,
TimeoutMs: 5000,
})
if err != nil {
return err
}
// result.Secret is the signing secret -- only available at creation time.
fmt.Printf("webhook created: id=%s secret=%s\n", result.Webhook.ID, result.Secret)The webhook signing secret is returned only once at creation time and is not stored in plain text. Store it securely (e.g., in your secrets manager). If you lose it, rotate it using auth.Webhooks().RotateSecret(ctx, webhookID).
Listing and managing webhooks04
// List all webhooks.
result, err := auth.Webhooks().List(ctx, &webhook.ListInput{Limit: 50})
// Get a specific webhook.
w, err := auth.Webhooks().GetByID(ctx, webhookID)
// Update a webhook (e.g., change subscribed events).
updated, err := auth.Webhooks().Update(ctx, webhookID, &webhook.UpdateInput{
Events: []string{"user.created", "user.deleted"},
IsActive: true,
})
// Deactivate (pause delivery without deleting).
err := auth.Webhooks().Deactivate(ctx, webhookID)
// Delete permanently.
err := auth.Webhooks().Delete(ctx, webhookID)
// Rotate the signing secret.
result, err := auth.Webhooks().RotateSecret(ctx, webhookID)
// result.NewSecret is the new secret -- only available here.Webhook payload05
Every webhook request is an HTTP POST with a JSON body:
{
"id": "awhke_01h455vb4pex5vsknk084sn02q",
"event": "auth.signin",
"app_id": "myapp",
"env_id": "aenv_01h455vb...",
"occurred_at": "2024-03-15T14:30:00Z",
"data": {
"user": {
"id": "ausr_01h455vb...",
"email": "[email protected]",
"display_name": "Alice Nguyen"
},
"session": {
"id": "ases_01h455vb...",
"ip": "203.0.113.42",
"user_agent": "Mozilla/5.0 ..."
}
}
}The data field shape varies by event type. Each event type's data schema is specific to what changed.
HMAC signature verification06
Every webhook request includes an X-Authsome-Signature header containing an HMAC-SHA256 signature of the raw request body. Verify this signature on your endpoint before processing the payload:
package webhookhandler
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"io"
"net/http"
)
func HandleAuthsomeWebhook(secret string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "cannot read body", http.StatusBadRequest)
return
}
// Verify HMAC-SHA256 signature.
sig := r.Header.Get("X-Authsome-Signature")
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(body)
expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(sig), []byte(expected)) {
http.Error(w, "invalid signature", http.StatusUnauthorized)
return
}
// Process the verified payload.
var payload map[string]any
json.Unmarshal(body, &payload)
// ...
w.WriteHeader(http.StatusOK)
}
}Signature headers
| Header | Description |
X-Authsome-Signature | sha256=<hex-encoded HMAC> |
X-Authsome-Event | The event type string (e.g. auth.signin) |
X-Authsome-Delivery | A unique UUID for this delivery attempt |
X-Authsome-Timestamp | Unix timestamp of delivery (use to reject old replays) |
Delivery and retry07
When Authsome fires a webhook:
The event payload is built and signed.
An HTTP POST is sent to the endpoint URL with a configurable timeout (
TimeoutMs, default 5000ms).Any 2xx response is considered a success.
On failure (non-2xx, timeout, or connection error), delivery is retried up to
MaxRetriestimes with exponential backoff.All delivery attempts (including failures) are logged in the webhook delivery log.
// View delivery attempts for a webhook.
deliveries, err := auth.Webhooks().ListDeliveries(ctx, webhookID, &webhook.ListDeliveriesInput{
Limit: 50,
})
for _, d := range deliveries {
fmt.Printf(" [%s] attempt=%d status=%d success=%v\n",
d.CreatedAt.Format(time.RFC3339),
d.Attempt,
d.ResponseStatus,
d.Success,
)
}
// Manually retry a failed delivery.
err := auth.Webhooks().RetryDelivery(ctx, webhookID, deliveryID)Relay bridge integration08
Relay is the Forge-ecosystem's event bus. When Relay is configured, Authsome publishes every event to Relay in addition to (or instead of) direct HTTP webhook delivery. This lets other services in your platform subscribe to authentication events without going through HTTP.
import (
"github.com/xraph/authsome"
"github.com/xraph/authsome/webhook/relay"
)
auth := authsome.New(
authsome.WithWebhookBridge(relay.NewBridge(
relay.WithEndpoint("https://relay.internal:8080"),
relay.WithAPIKey(os.Getenv("RELAY_API_KEY")),
relay.WithTopic("authsome.events"),
relay.WithAsync(true),
)),
)HTTP API endpoints09
| Method | Path | Description |
POST | /webhooks | Create a new webhook |
GET | /webhooks | List all webhooks |
GET | /webhooks/:webhook_id | Get a webhook by ID |
PATCH | /webhooks/:webhook_id | Update a webhook |
DELETE | /webhooks/:webhook_id | Delete a webhook |
POST | /webhooks/:webhook_id/deactivate | Pause webhook delivery |
POST | /webhooks/:webhook_id/activate | Resume webhook delivery |
POST | /webhooks/:webhook_id/rotate-secret | Rotate the signing secret |
GET | /webhooks/:webhook_id/deliveries | List delivery attempts |
POST | /webhooks/:webhook_id/deliveries/:delivery_id/retry | Retry a failed delivery |
POST | /webhooks/test | Send a test event to a webhook URL |