Core Concepts

Events

AuthEventBus, listen to post-action events for analytics, audit, and monitoring.

AuthEventBus broadcasts what already happened. Unlike Callbacks →, a listener can't block or change anything, it's pure notification: analytics, audit logs, monitoring.

Each AuthyraClient owns its own bus (not a singleton), so multiple clients in the same process stay fully isolated.


Subscribing

// Typed subscription
client.events.on<SignInEvent>((e) {
  analytics.track('sign_in', {'provider': e.providerName, 'new_user': e.isNewUser});
});

// Raw stream, every event, useful for a single audit sink
client.events.stream.listen((e) {
  auditLog.write(e.toJson());
});

// Unsubscribe
client.events.off<SignInEvent>(myListener);

A listener runs synchronously during emit; an exception thrown inside one is caught and logged, it never propagates back to the caller that triggered the action.


Event catalogue

EventEmitted when
SignInEventSign-in succeeded. Carries user, providerName, isNewUser, duration.
SignInFailedEventA sign-in attempt failed. Carries providerName, errorMessage, errorCode.
SignOutEventSign-out completed. Carries user, sessionDuration.
SessionCreatedEventA session was written to the registry, first sign-in or a repeat sign-in refreshing an existing session. Carries session, isNewUser.
SessionExpiredEventAn active session expired and was cleared, from exhausted refresh or an explicit expiry check. Carries user, expiredAt.
TokenRefreshEventA refresh attempt completed, success or failure. Carries user, success, errorMessage.
AccountSwitchEventThe active account changed via AccountManager.switchTo(). Carries fromUser, toUser.
AccountRemovedEventAn account was explicitly removed via AccountManager.signOut(userId), distinct from expiry. Carries userId, email.

Every event has a timestamp and a toJson() for structured logging.


Example: audit log

client.events.stream.listen((event) {
  auditLog.write({
    'event': event.runtimeType.toString(),
    ...event.toJson(),
  });
});

Example: react to forced sign-out

client.events.on<SessionExpiredEvent>((e) {
  showSnackBar('Your session expired. Please sign in again.');
});

client.events.on<TokenRefreshEvent>((e) {
  if (!e.success) showReAuthPrompt();
});

Example: multi-account analytics

client.events.on<AccountSwitchEvent>((e) {
  analytics.track('account_switch', {'from': e.fromUser.id, 'to': e.toUser.id});
});

client.events.on<AccountRemovedEvent>((e) {
  analytics.track('account_removed', {'user': e.userId});
});

Events vs plugins vs callbacks

MechanismCan block?Use for
AuthCallbacksYesRate limiting, deny lists, authorization checks
AuthyraPluginNoCross-cutting side effects installed once (audit logging, rate-limit bookkeeping)
AuthEventBusNoAd hoc listeners registered anywhere, analytics, one-off UI reactions

AuthyraPlugin hooks and AuthEventBus events overlap in spirit; reach for a plugin when the behaviour ships with your app's setup, and for client.events.on<T>() when you want a quick listener local to one screen or test.


See also

Copyright © 2026