Skip to main content

Auth Service — Event Schemas

Status: populated Owner: Platform Engineering + Security Last updated: 2026-04-19

Change log

  • v1.2 (2026-04-19) — Added SSO / multi-IdP events: auth.idp.configured.v1, auth.idp.disabled.v1, auth.idp.removed.v1, auth.external_identity.linked.v1, auth.external_identity.unlinked.v1, auth.sso.session.started.v1, auth.sso.session.failed.v1. auth.user.logged_in.v1.method widened to include provider ids.

1. Produced

SubjectStreamRetention
auth.user.registered.v1AUTH_EVENTS30d
auth.user.logged_in.v1AUTH_EVENTS7d
auth.user.locked.v1AUTH_EVENTS30d
auth.user.erased.v1AUTH_EVENTS365d (audit)
auth.api_key.issued.v1AUTH_EVENTS30d
auth.api_key.revoked.v1AUTH_EVENTS30d
auth.api_key.rotated.v1AUTH_EVENTS30d
auth.jwks.rotated.v1AUTH_EVENTS90d
auth.role.assigned.v1AUTH_EVENTS30d
auth.idp.configured.v1AUTH_EVENTS365d (audit)
auth.idp.disabled.v1AUTH_EVENTS365d (audit)
auth.idp.removed.v1AUTH_EVENTS365d (audit)
auth.external_identity.linked.v1AUTH_EVENTS90d
auth.external_identity.unlinked.v1AUTH_EVENTS90d
auth.sso.session.started.v1AUTH_EVENTS30d
auth.sso.session.failed.v1AUTH_EVENTS90d (security)

2. Schemas (examples)

auth.user.logged_in.v1

interface UserLoggedIn {
schemaVersion: '1';
userId: string;
accountId: string;
tenantId: string;
providerId: string; // 'keycloak' | 'tenant-oidc:<tid>' | 'tenant-saml:<tid>' | 'firebase-legacy' | 'native' | 'api_key'
method: 'password' | 'oidc' | 'saml' | 'firebase' | 'api_key';
mfa: boolean;
ip: string; // hashed in downstream
userAgent: string;
at: string;
}

auth.idp.configured.v1

interface IdpConfigured {
schemaVersion: '1';
providerId: string;
tenantId: string;
kind: 'oidc' | 'saml' | 'firebase';
discoveryUrl?: string;
metadataRef?: string;
keycloakIdpAlias?: string;
isDefault: boolean;
configuredBy: string; // userId
at: string;
}

auth.external_identity.linked.v1

interface ExternalIdentityLinked {
schemaVersion: '1';
userId: string;
tenantId: string;
providerId: string;
externalSubjectHash: string; // sha256 of external sub; raw sub never emitted
at: string;
}

auth.sso.session.failed.v1

interface SsoSessionFailed {
schemaVersion: '1';
providerId: string;
tenantId: string;
reason: 'signature_invalid' | 'issuer_mismatch' | 'reserved_domain' | 'claims_incomplete' | 'replay' | 'other';
ip: string; // hashed downstream
userAgent: string;
traceId: string;
at: string;
}

auth.api_key.issued.v1

interface ApiKeyIssued {
schemaVersion: '1';
keyId: string;
accountId: string;
tenantId: string;
scopes: string[];
createdBy: string; // userId
expiresAt?: string;
at: string;
// NOTE: never include the raw key
}

auth.jwks.rotated.v1

interface JwksRotated {
schemaVersion: '1';
previousKid: string;
newActiveKid: string;
retiringKid: string;
at: string;
}

3. Consumed

SubjectProducerPurpose
tenant.erased.v1 (if tenant-service exists later)tenant-serviceCascade user / account erasure

4. PII

  • email, userId, ip are PII. Downstream consumers must not persist unmasked.
  • ip hashed in analytics.
  • No passwords, password hashes, or raw API keys in any event.

5. Outbox pattern

User / account / api-key changes use transactional outbox: write event row to auth.outbox in same PG transaction as aggregate change; publisher relay publishes to NATS with retry + ACK.