Skip to content

Webhook Integration

logi notifies your RP of the following events.

Event catalog

event_typeDelivery pathWhen
user.deletedlegacyA user account is deleted
user.unlinkedlegacyA partner app is disconnected
consent.revokedlegacyA scope consent is withdrawn
token.revokedlegacyAn access/refresh token is force-invalidated
user.mergedPLAN-L outboxTwo logi accounts were merged — for the full payload, see Account Merge + Merge Idempotency
user.grants_revokedPLAN-L outboxThe user revoked every grant they had given the RP, in one go
webhook_key.compromisedPLAN-L outboxAn operator force-retired a webhook signing key (the RP must rotate immediately)

Events whose Delivery path is PLAN-L arrive only with the new signature format (t=,kid=,v1=), while legacy events arrive with the old format (sha256=) for the time being. For the detailed format branching, see below.

Configuration

Specify webhook_url when registering the app. Change it with PATCH /api/v1/applications/:id.

🛡️ URL policy (P1 SSRF defense)

  • Only https:// is allowed (with http://localhost and http://127.0.0.1 as exceptions in development).
  • The host is DNS-resolved and validated both at registration and at dispatch time:
    • Private IP ranges are blocked (10/8, 172.16/12, 192.168/16, 127/8, 169.254/16, 100.64/10)
    • Link-local / multicast are blocked
    • IPv6 private/loopback/link-local are blocked the same way
  • DNS rebinding defense: connect directly to the validated IP, while keeping the original domain for the SNI/Host header.
  • On a violation, that event is treated as a delivery failure with the reason ssrf_blocked.

Secret rotation

You must rotate the webhook signing secret. Until you do, signing falls back to BCrypt, and in that case the response includes the X-Logi-Secret-Deprecated: true and Deprecation headers — we recommend rotating from the developer portal.

bash
curl -X POST -H "Authorization: Bearer $PAK" \
  https://api.1pass.dev/api/v1/applications/:id/rotate_webhook_secret

The rotation response exposes the plaintext only once. Use it for verification afterward.

Expiry policy

  • Default TTL: 1 year
  • Admins/developers are notified starting 30 days before expiry (audit log + email in Phase 2)
  • Attempting to issue a token with an expired client_secret is rejected with invalid_client

Request format — two signature formats coexist

logi currently uses two signature formats at the same time. Your RP's verifier must accept both.

① PLAN-L outbox (canonical; new events use this path)

Dispatched by Logi::Webhooks::DeliveryJob. All events from PLAN-L onward — user.merged, user.grants_revoked, webhook_key.compromised, and so on — take this path.

http
POST https://your.app/hooks/logi
Content-Type: application/json
X-Logi-Event: user.merged
X-Logi-Event-Id: 01HV...               # idempotency key (`event_id`)
X-Logi-Delivery-Id: 12345              # identical across retries
X-Logi-Signature: t=1735000000,kid=whk_2025q4_a1,v1=a3d9f0...

{"event_id":"01HV...","event_type":"user.merged","data":{...},"created_at":"..."}

The signature is HMAC-SHA256(secret_for_kid, raw_body) — look up the key by kid, then verify.

② Legacy WebhookDispatchJob (deprecated, back-compat)

The existing four events (user.deleted, user.unlinked, consent.revoked, token.revoked) are still dispatched via this path.

http
POST https://your.app/hooks/logi
Content-Type: application/json
X-Logi-Event: user.deleted
X-Logi-Delivery-Id: 12345
X-Logi-Timestamp: 1735000000
X-Logi-Signature: sha256=a3d9f0...

{"id":12345,"event_type":"user.deleted","payload":{"user_id":42},"created_at":"..."}

The signature is HMAC-SHA256(webhook_secret, raw_body) — a single secret.

Verifier-writing guide: the HMAC signature verification page has verifier examples that handle both formats — branch to PLAN-L if the header value contains a ,, and to legacy if it starts with sha256=.

Retry policy

Legacy path

  • Up to 10 attempts (within 24h)
  • Exponential backoff: 1m → 2m → 4m → 8m → 16m → 32m → 60m → 120m → 240m → 480m
  • A 2xx response means delivery is complete. 3xx/4xx/5xx and timeouts are retried.
  • If all 10 fail → mark failed_at and surface it in the developer portal

PLAN-L outbox path

  • Up to 5 attempts — Linear-style backoff: 1m → 5m → 30m → 2h → 6h
  • 2xx → delivery complete
  • 408 / 429 / 5xx → retried
  • Any other 4xx → straight to DLQ (interpreted as the RP explicitly rejecting it)
  • If all 5 fail → DLQ → developer portal + mark webhook_outbox_entries.dlq_at

Next: HMAC signature verification →

Identity가 제품의 신뢰를 만듭니다.