API Reference

AuthyraClient

Complete API reference for AuthyraClient, the dependency-injected orchestration layer.

Overview

AuthyraClient is the dependency-injected core of Authyra. It holds real internal state (the session registry, an event bus, its initialized flag) but no global state: nothing is static or ambient, so it's fully injectable and trivially testable.

import 'package:authyra/authyra.dart';

final client = AuthyraClient(
  providers: [GoogleProvider(clientId: 'YOUR_CLIENT_ID')],
  storage:   InMemoryStorage(),
  config:    const AuthConfig(),
);

You rarely interact with AuthyraClient directly in application code, AuthyraInstance (via Authyra.instance) is the app-facing singleton. Use AuthyraClient directly when writing tests or building backend services.


Constructor

AuthyraClient({
  required List<AuthProvider> providers,
  required AuthStorage        storage,
  AuthCallbacks?              callbacks,
  AuthConfig                  config = const AuthConfig(),
  List<AuthyraPlugin>?        plugins,
})
ParameterTypeDescription
providersList<AuthProvider>One or more auth strategies. Each must have a unique id.
storageAuthStoragePersistence backend. Use InMemoryStorage for tests.
callbacksAuthCallbacks?Optional gate for sign-in/sign-out/switch/refresh/remove; see Callbacks.
configAuthConfigOptional tuning: token lifetime, auto-refresh, refresh threshold.
pluginsList<AuthyraPlugin>?Optional observers (audit logging, analytics); can't block an action.

The constructor validates provider IDs synchronously and throws ProviderAlreadyRegisteredException on duplicates.


Methods

initialize()

Prepares the client for use. Must be called once before any other method.

Future<void> initialize()

What it does:

  • Calls storage.initialize().
  • Loads and deserialises the SessionRegistry from storage.
  • Restores the active session if one exists.
  • Emits an initial AuthState on authStateStream.

Throws: StorageException if the storage backend cannot be initialised.

await client.initialize();

signIn()

Authenticates a user via the named provider.

Future<AuthUser> signIn(
  String providerId, {
  AuthSignInParams? params,
})
ParameterTypeDescription
providerIdStringThe id of the registered provider to use.
paramsAuthSignInParams?Typed, provider-specific input: CredentialsSignInParams, OAuth2SignInParams, or your own subclass.

Returns AuthUser, the authenticated user's profile.

Throws:

  • ProviderNotFoundException, no provider with that id is registered.
  • AuthenticationFailedException, the provider returned null (wrong credentials), a callback denied the sign-in, or an infrastructure error occurred.
final user = await client.signIn('email', params: CredentialsSignInParams(
  email: 'alice@example.com',
  password: 'secret',
));

signOut()

Signs out the currently active account.

Future<void> signOut()

Steps:

  1. Retrieves the active session.
  2. If the provider has supportsSignOut: true, calls provider.signOut(userId).
  3. Removes the session from SessionManager.
  4. Emits AuthState.unauthenticated() on authStateStream.
await client.signOut();

refreshSession()

Silently refreshes the active session's access token.

Future<bool> refreshSession()

Returns true if the token was refreshed successfully, false if the refresh token is invalid or the provider does not support refresh.

Called automatically by AuthyraInstance, you rarely need to call this directly.

final refreshed = await client.refreshSession();
if (!refreshed) {
  // Token is invalid, the session has been cleared.
}

getSession()

Returns the active AuthSession, or null if no user is signed in.

Future<AuthSession?> getSession()
final session = await client.getSession();
print(session?.accessToken);

getUser()

Returns the active AuthUser, or null if not authenticated.

Future<AuthUser?> getUser()

registerProvider()

Dynamically adds a provider after construction.

void registerProvider(AuthProvider provider)

Useful for providers that require runtime configuration (e.g., a tenant-specific OAuth client ID):

client.registerProvider(
  OAuth2Provider(config: tenantConfig),
);

Throws InvalidProviderConfigException if provider.id is empty, or ProviderAlreadyRegisteredException if a provider with the same id is already registered.


Properties

authStateStream

Broadcast stream of AuthState changes. Deduplicated, identical consecutive states are not re-emitted.

Stream<AuthState> get authStateStream
client.authStateStream.listen((state) {
  if (state.isAuthenticated) {
    print('Signed in as ${state.user!.email}');
  }
});

sessionStream

Broadcast stream of the raw AuthSession, or null on sign-out.

Stream<AuthSession?> get sessionStream

accounts

Lazy accessor for the AccountManager. Manages the multi-account session registry.

AccountManager get accounts
await client.accounts.getAll();          // List<AuthUser>
await client.accounts.getAllSessions();  // List<AuthSession>, with tokens/expiry
await client.accounts.switchTo(id);      // activate a different session
await client.accounts.signOut(id);       // sign out one account
await client.accounts.signOutAll();      // clear all sessions
await client.accounts.cleanExpired();    // prune expired sessions, returns count removed
await client.accounts.isValid(id);       // has a registered, non-expired session?
await client.accounts.getTokenFor(id);   // access token for a non-active account

See AccountManager API → for the full surface.


isInitialized

true after initialize() has completed successfully.

bool get isInitialized

AuthConfig

Fine-tune the client's session behaviour:

const AuthConfig({
  int tokenLifetime      = 3600,  // seconds before access token expires
  bool autoRefresh       = true,  // refresh token automatically when expiring
  int refreshBeforeExpiry = 300,  // seconds before expiry to trigger refresh
})
final client = AuthyraClient(
  providers: [...],
  storage:   storage,
  config: const AuthConfig(
    tokenLifetime:       7200,  // 2 hours
    refreshBeforeExpiry: 600,   // refresh 10 minutes early
  ),
);

There is no account-count limit in AuthConfig; SessionManager keeps every signed-in account until you explicitly sign it out.


Testing

Prefer AuthyraClient directly in unit tests, no singleton to reset between tests:

import 'package:test/test.dart';
import 'package:authyra/authyra.dart';

void main() {
  late AuthyraClient client;

  setUp(() async {
    client = AuthyraClient(
      providers: [
        CredentialsProvider(
          id: 'email',
          authorize: (creds) async {
            if (creds?.password == 'correct') {
              return AuthUser(id: '1', email: creds!.email);
            }
            return null;
          },
        ),
      ],
      storage: InMemoryStorage(),
    );
    await client.initialize();
  });

  test('returns user on valid credentials', () async {
    final user = await client.signIn('email', params: CredentialsSignInParams(
      email: 'alice@example.com',
      password: 'correct',
    ));
    expect(user.email, 'alice@example.com');
  });

  test('throws on invalid credentials', () async {
    expect(
      () => client.signIn('email', params: CredentialsSignInParams(email: 'a@b.com', password: 'wrong')),
      throwsA(isA<AuthenticationFailedException>()),
    );
  });

  test('isAuthenticated after sign in', () async {
    await client.signIn('email', params: CredentialsSignInParams(email: 'a@b.com', password: 'correct'));
    final session = await client.getSession();
    expect(session, isNotNull);
  });
}
Copyright © 2026