From Firebase Auth
This isn't "Firebase is worse, switch." If Firebase as your backend works for you, keep it, OAuth2Provider/ProxyOAuthProvider can even sit in front of it. This page is for when you're moving off Firebase as your identity backend, or adding a second provider alongside it and want one consistent app-side API.
Concept mapping
| Firebase Auth | Authyra |
|---|---|
FirebaseAuth.instance | Authyra.instance (or an injected AuthyraClient) |
User | AuthUser |
FirebaseAuth.instance.authStateChanges() | Authyra.instance.authStateChanges |
signInWithEmailAndPassword | signIn('email', params: CredentialsSignInParams(...)) against your own CredentialsProvider |
signInWithCredential (Google, etc.) | signIn('google') via GoogleProvider, or your own OAuth2Provider |
currentUser | Authyra.instance.currentUser (synchronous, no FutureBuilder) |
getIdToken() | Authyra.instance.getAccessToken() |
signOut() | Authyra.instance.signOut() |
Multiple FirebaseApp instances for multi-account | Authyra.instance.accounts (switchTo, signOut(userId), signOutAll), one AuthyraClient, no app-instance juggling |
What moves, what doesn't
Your backend contract changes. Firebase issues its own tokens and manages its own user database. With Authyra, CredentialsProvider/OAuth2Provider call your backend (or a provider you configure), Authyra never becomes the identity source itself. If you're keeping Firebase as the backend, wrap it: implement AuthProvider.signIn to call Firebase's REST API or the Firebase Admin SDK from your own server, or reuse firebase_auth directly inside your provider and translate its result into an AuthSignInResult.
Session persistence changes. Firebase's SDK manages its own local persistence. Authyra needs an explicit AuthStorage, SecureAuthStorage (Flutter) is the equivalent of "just works," Keychain/Keystore-backed.
Example: email/password
// Firebase
final credential = await FirebaseAuth.instance.signInWithEmailAndPassword(
email: email,
password: password,
);
final user = credential.user;
// Authyra, against your own backend
final user = await Authyra.instance.signIn('email', params: CredentialsSignInParams(
email: email,
password: password,
));
The authorize callback you write for CredentialsProvider is where you'd call Firebase (or your own API) if you're keeping that backend:
CredentialsProvider.withTokens(
id: 'email',
authorize: (creds) async {
try {
final cred = await FirebaseAuth.instance.signInWithEmailAndPassword(
email: creds?.email ?? '', password: creds?.password ?? '',
);
final token = await cred.user!.getIdToken();
return AuthSignInResult(
user: AuthUser(id: cred.user!.uid, email: cred.user!.email),
accessToken: token,
expiresAt: DateTime.now().add(const Duration(hours: 1)),
);
} on FirebaseAuthException {
return null; // wrong credentials
}
},
)
Example: reactive state
// Firebase
StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
final user = snapshot.data;
return user != null ? HomePage() : LoginPage();
},
)
// Authyra
StreamBuilder<AuthState>(
stream: Authyra.instance.authStateChanges,
builder: (context, snapshot) {
final state = snapshot.data ?? AuthState.unauthenticated();
return state.isAuthenticated ? HomePage(user: state.user!) : LoginPage();
},
)