They use the same webhook system as the rest of sajn: the same event body, Standard Webhooks
signing, retries, and delivery log. To receive them, add
login.completed and login.failed to
the events of a webhook. For setup, see Webhooks.
Why you might want them
The normal flow is synchronous: the user is redirected back and you exchange the code. Webhooks matter for the case that redirect never arrives. The common one is mobile. A user opens the login in an in-app browser, authenticates, and closes the browser before it redirects. They believe they logged in; your app never heard anything. sajn completes the authentication server-side regardless — a background watchdog finishes the flow if the browser stops responding — so the result exists. The webhook is how you learn about it.If you use OpenID Connect, a
login.completed webhook can’t be exchanged for an
id_token — the authorization code goes to the browser and expires in 60 seconds. Treat the
webhook as a signal to prompt the user to try again, or to reconcile your own records. With the
Session API you can act on it directly: GET the session for the claims.login.completed
data.object:
login.failed
data.object has the same sessionId, clientId, mode, and state as login.completed,
plus reason, the BankID hint code, and failedAt.
This fires only for terminal failures. Recoverable ones — the user cancelled, the QR failed to
scan, the app was not found — do not fire, because the login page offers a retry within the same
session and notifying on each would flood your endpoint.
Typical reason values are expiredTransaction and certificateErr. For the full list, see
Errors.
Delivery
Login events are delivered like every other sajn event: signed according to Standard Webhooks, retried with backoff, and visible in the delivery log under Inställningar → Utvecklare → Webhooks. Two rules worth repeating:- Verify the signature with the
webhook-id,webhook-timestamp, andwebhook-signatureheaders before you act on an event. See Verify signatures. - Expect duplicates. Deliveries are at-least-once. The event
idis stable per event, anddata.object.idonlogin.completedis stable per authentication. Use either as an idempotency key.

