Introduction
What is Authyra?
Authyra is not another identity provider. It's the orchestration layer between your Flutter app and whatever auth infrastructure you already have, a custom API, Auth0, Firebase, Supabase, or a raw OIDC provider.
Most Flutter auth packages bundle the protocol, the identity provider, and your app's session plumbing together. Authyra sits one layer above that: it doesn't talk to any external service itself, it orchestrates the providers you configure and owns the client-side session lifecycle on top of them, sign-in, session persistence, token refresh, and multi-account state, without coupling to a backend, a navigation framework, or a UI library.
Two packages
Authyra ships as two complementary packages:
Sign in with Apple lives in a third package, authyra_apple, built on the native sign_in_with_apple SDK rather than a browser-based OAuth2 flow. See Apple Provider →.
Rule of thumb: depend on authyra_flutter for Flutter apps. Depend on authyra for Dart backends, unit tests, or any non-Flutter Dart target.
Core principles
1. Pure logic, no framework coupling
AuthyraClient is a plain Dart class, no BuildContext, no ChangeNotifier, no platform channel. The same code runs in a Flutter app and in a dart test suite.
2. Everything is an interface
AuthProvider and AuthStorage are abstract classes you implement:
- Credentials or OAuth2 plug in through the same
AuthProviderinterface. Implement it directly for a strategy Authyra doesn't ship (SAML, magic link, phone OTP, anything else). - Any storage backend,
flutter_secure_storage, Redis, SQLite, an in-memory map, is swappable. - Tests replace providers and storage with three-line classes. No mocking framework needed.
3. Reactive by default
Every state change emits on authStateChanges: Stream<AuthState>. Wire it to StreamBuilder, Riverpod, Bloc, or a GoRouter redirect. AuthState uses Equatable, so identical consecutive states are deduplicated, no spurious rebuilds.
4. Synchronous state when you need it
AuthyraInstance (the singleton wrapper) maintains a synchronous cache:
Authyra.instance.currentUser // AuthUser? no await
Authyra.instance.isAuthenticated // bool no await
Authyra.instance.currentState // AuthState no await
Safe to call in build() methods without FutureBuilder.
Package split: what lives where
| Component | authyra | authyra_flutter | authyra_apple |
|---|---|---|---|
AuthyraClient | ✓ | re-exported | - |
AuthyraInstance / Authyra | ✓ | re-exported | - |
AuthProvider interface | ✓ | re-exported | - |
AuthStorage interface | ✓ | re-exported | - |
CredentialsProvider | ✓ | re-exported | - |
SessionManager | ✓ | re-exported | - |
AccountManager | ✓ | re-exported | - |
InMemoryStorage | ✓ | re-exported | - |
OAuth2Provider | - | ✓ | - |
GoogleProvider | - | ✓ | - |
GitHubProvider | - | ✓ | - |
ProxyOAuthProvider | - | ✓ | - |
SecureAuthStorage | - | ✓ | - |
OAuth2CallbackHandler | - | ✓ | - |
AppleProvider | - | - | ✓ |