Auth Container NATS Events
Authlance core mainly use NATS JetStream to publish events about user authentication, subscription lifecycle, payments, and license status changes. For example you listen on an event to trigger welcome emails, authentication emails, or to react to subscription changes. It also uses it to gurantee reliable delivery of Stripe webhooks to the payment processing pipeline.
Event Summary
| Subject | Published from | Trigger | Payload |
|---|---|---|---|
user.authenticated | Auth service | Successful POST /authlance/identity/me exchange | Normalized user payload |
subscription.created | Subscription events handler | A group subscription is created or its tier changes | { "tierName", "group", "status" } |
subscription.updated | Subscription events handler | A payment event refreshes the subscription status | { "tierName", "group", "status" } |
subscription.canceled | Subscription events handler | Stripe (or admin) cancels a subscription | { "user", "group", "status" } |
stripe.webhook.event | Payments service | Any incoming Stripe webhook | { "event": stripe.Event } |
payment.success | Payments service | invoice.payment_succeeded after async processing | Subscription/payment metadata |
payment.declined | Payments service | invoice.payment_failed after async processing | Subscription/payment metadata |
license.updated | License manager | License reload returns a new state | license.Status |
license.expiring | License manager | License enters a grace period or hits a configured day threshold | license.Status |
license.invalid | License manager | License transitions to invalid (and not grace) | license.Status |
mail.send | Mail API | Internal courier request reaches /authlance/identity/email | MailPayload |
Each subject is described in more detail below, including JSON samples derived from the structs embedded in the container.
Authentication
user.authenticated
- Publisher: Auth service (login endpoint)
- When: After a valid Kratos session is exchanged for a JWT via
POST /authlance/identity/me. - Payload: User JSON including identity ID, names, email, roles, group memberships, and verification flags.
{
"identity": "f31c…",
"firstName": "Jane",
"lastName": "Doe",
"email": "jane@example.com",
"roles": ["user", "group-admin"],
"groupRoles": [{"group": "acme", "role": "group-admin"}],
"groups": ["acme"],
"verified": true,
"state": "active",
"avatar": null,
"birthDate": "1990-05-12",
"gender": "female"
}
Use this event to track logins or hydrate session caches without hitting the Auth API again.
Subscription lifecycle
All subscription subjects are published from the subscription events handler inside the auth service. The handler reacts to admin bootstrap events and to Stripe-derived payment events.
subscription.created
Emitted whenever a group receives its first active subscription or a tier changes. Payload:
{
"tierName": "pro",
"group": {
"id": 42,
"name": "acme",
"longName": "Acme Inc.",
"avatar": null,
"description": null,
"url": null
},
"status": "active"
}
subscription.updated
Sent after Stripe confirms a payment succeeded and refreshes the billing info or status. The JSON shape matches subscription.created, but status reflects the new state (active, past_due, etc.).
subscription.canceled
Published when Stripe confirms a cancellation. Payload:
{
"user": "kratos-identity-id",
"group": {
"id": 42,
"name": "acme"
},
"status": "cancelled"
}
Subscribers can use this to revoke access or start win-back campaigns.
Payments
stripe.webhook.event
This is internally handled and is part of the payment processing flow. Do not subscribe to this subject unless you need to monitor all raw Stripe events.
- Publisher: Payments service (Stripe webhook endpoint)
- When: Every Stripe webhook POST that passes signature validation.
- Payload: Wrapper around the raw Stripe event.
{
"event": {
"id": "evt_1P0…",
"type": "invoice.payment_succeeded",
"created": 1718143437,
"data": {
"object": {
"id": "in_1P0…",
"subscription": "sub_123",
"customer": "cus_456",
"amount_paid": 9900
}
}
}
}
This subject fans in to the Stripe webhook worker, which handles the event asynchronously and may emit the downstream payment subjects below.
payment.success
Triggered by the payments event handler once an invoice.payment_succeeded event finishes processing. Payload contains the subscription ID, Stripe customer ID, amount, and the resulting subscription status.
{
"subscriptionId": "sub_123",
"stripeCustomerId": "cus_456",
"amount": "99.00",
"subscription_status": "active"
}
Only the fields available from the Stripe invoice/session are populated today; all other struct fields remain empty strings or null.
payment.declined
Published from the payments event handler after an invoice.payment_failed event. Payload contains the subscription ID, Stripe customer ID, amount, and the failure reason.
{
"subscriptionId": "sub_123",
"stripeCustomerId": "cus_456",
"amount": "99.00",
"reason": "Payment failed"
}
Use this subject to kick off dunning workflows or notify account owners.
License state
The embedded license manager reloads the license on startup and on a timer. Whenever the status changes it emits up to three subjects, all sharing the same payload (license.Status).
{
"plan": "enterprise",
"valid": true,
"grace": false,
"exp": "2024-12-31T23:59:59Z",
"domain": "example.com",
"daysRemaining": 182,
"licenseId": "lic_abc123"
}
license.updatedis published on every status change (including initial load).license.expiringfires whenDaysRemaininghits 30/14/7/3/1 or when the state transitions into grace.license.invalidfires when the license becomes invalid (not grace) after previously being valid/grace.
mail.send
- Publisher: Mail API (internal
/authlance/identity/emailroutes) - When: Kratos courier relays an event to the internal Authlance endpoint with valid basic-auth credentials.
- Payload: Same
MailPayloadreceived over HTTP.
{
"to": "user@example.com",
"from": "no-reply@example.com",
"templateId": "password-reset",
"templateModel": {
"email": "user@example.com",
"name": {"first": "Jane", "last": "Doe"},
"recovery_url": "https://example.com/reset?token=…",
"verification_url": null,
"recovery_code": null,
"verification_code": null
}
}
Workers can subscribe to mail.send to deliver transactional emails without blocking the HTTP request.
Usage tips
- When creating consumers, remember that JetStream stream names replace dots with underscores (subject names become stream names by swapping
.for_). - Payloads are never compressed; you can decode them with the standard JSON decoder in any language.
- Consider durable consumers per subject so retries do not redeliver already processed events.
Next steps: combine this reference with the Auth Container Commands to automate both operational tasks and event-driven workflows.