Skip to content

feat(ui_oauth_twitter)!: replace twitter_login with signInWithProvider - #697

Open
demolaf wants to merge 12 commits into
mainfrom
oauth/twitter-signinwithprovider
Open

demolaf wants to merge 12 commits into
mainfrom
oauth/twitter-signinwithprovider

Conversation

@demolaf

@demolaf demolaf commented Sep 14, 2026

Copy link
Copy Markdown
Member

Closes #696.

twitter_login has not published a release since July 2023, and its Android build.gradle declares no namespace while pinning AGP 4.1.0. Its namespace fix merged upstream in 2024 but was never released, which is why tests/android was held at AGP 8.7.3 with a hardcoded compileSdk, and why #693 could not adopt flutter_web_auth_2.

TwitterProvider now signs in through auth.signInWithProvider on Android and iOS, mirroring AppleProvider, so Firebase performs the OAuth dance and the Twitter API key and secret move out of the app binary into the Firebase console. macOS and Windows keep the vendored OAuth 1.0a flow, since neither can use signInWithProvider: the C++ SDK rejects it on Windows (firebase/flutterfire#13231), and on macOS the generic OAuth flow is declared #if os(iOS) in the Firebase Apple SDK, so there is nothing for the plugin to call. That is why apiKey and apiSecretKey remain, now as optional parameters. With twitter_login gone, compileSdk returns to flutter.compileSdkVersion and AGP moves to 8.9.1, unblocking #693.

⚠️ Breaking change: consumers must set their Twitter app's callback URL to https://<project>.firebaseapp.com/__/auth/handler, add the Encoded App ID URL scheme on iOS, and register their SHA-1 on Android. Nothing stops compiling, so a debug-only diagnostic warns once when the API keys are passed on a platform that now ignores them. AuthAction.none throws UnsupportedError on Android and iOS, since a credential cannot be obtained without also creating a session, and the credential handed to onCredentialLinked is now a plain AuthCredential rather than an OAuthCredential. macOS and Windows behaviour is unchanged.

Preview

  • Android
untitled.webm
  • iOS
Simulator.Screen.Recording.-.iPhone.17.-.2026-09-15.at.14.33.26.mov

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request removes the dependency on the twitter_login package, transitioning the Twitter sign-in flow to use Firebase's native signInWithProvider on Android, iOS, and macOS. Consequently, apiKey and apiSecretKey are now optional and only required on Windows. The integration tests have been updated to mock the Firebase Auth provider instead of the third-party Twitter login client. Regarding the feedback, a critical issue was identified where a null auth.currentUser during a link or upgrade action would silently fail due to a null-shorting operator, leaving the UI hanging; adding an explicit null check and error notification is recommended.

Comment thread packages/firebase_ui_oauth_twitter/lib/src/provider.dart
@demolaf
demolaf force-pushed the oauth/twitter-signinwithprovider branch 3 times, most recently from 8d34ab7 to 007e379 Compare September 14, 2026 22:56
@demolaf
demolaf marked this pull request as ready for review September 15, 2026 09:17
@demolaf
demolaf marked this pull request as draft September 15, 2026 10:15
@demolaf
demolaf marked this pull request as ready for review September 15, 2026 10:26
twitter_login has not published since July 2023 and ships an Android build.gradle with no namespace that pins AGP 4.1.0, which capped this repo at AGP 8.7.3 and blocked #693 from using flutter_web_auth_2.

TwitterProvider now signs in through auth.signInWithProvider on Android and iOS, mirroring AppleProvider, so Firebase performs the OAuth dance and the Twitter API key and secret move out of the app binary into the Firebase console. macOS and Windows keep the vendored OAuth 1.0a flow, which is why apiKey and apiSecretKey survive as optional parameters rather than being removed.

macOS stays on the desktop flow because signInWithProvider is not available to it: FLTFirebaseAuthPlugin.swift carves out Apple and Game Center, then fails every other provider under `#if os(macOS)` with unsupported-platform. Android has no equivalent restriction.

- AuthAction.none throws UnsupportedError on Android and iOS, since signInWithProvider cannot return a credential without also creating a session.
- Anonymous users are upgraded with linkWithProvider so the anonymous uid survives sign in.
- A debug-only diagnostic warns once when apiKey or apiSecretKey are passed on a platform that now ignores them.
- Restores compileSdk to flutter.compileSdkVersion and bumps AGP to 8.9.1, now that nothing pins it.

BREAKING CHANGE: consumers must set the Twitter app callback URL to the Firebase auth handler, add the Encoded App ID URL scheme on iOS, and register their SHA-1 on Android. AuthAction.none now throws on Android and iOS, and the credential passed to onCredentialLinked is a plain AuthCredential rather than an OAuthCredential.
…in user

AuthAction.link with no FirebaseAuth.currentUser null-shorted the linkWithProvider call, so the flow neither completed nor reported an error and the UI stayed in its loading state. The credential path this replaced raised through auth.currentUser!, so a null user was at least surfaced.

Reports a FirebaseAuthException instead, which reaches AuthFailed rather than escaping as an unhandled Error the way a StateError would.
The pin comment claimed v6 while the pinned SHA is v6.2.0, and upstream has since moved the v6 tag to v6.3.0. zizmor flagged the mismatch as a medium severity finding, which blocks the workflow check.

Corrects the comment rather than moving the pin, so the action version CI runs is unchanged.
Rewrites the Twitter section around the flow Firebase now performs on Android and iOS: enable the provider in the console, point the X app callback URL at the Firebase auth handler, then add the encoded app ID URL scheme on iOS and the SHA-1 on Android. The twitter_login install step is gone, and the API key and secret move into their own macOS and Windows section, since those are the only platforms that still need them.

Adds the encoded app ID scheme to the firebase_ui_auth example and drops the ffire:// redirect it passed for twitter_login, which no longer takes part in either flow.
AGP 8.9.1 requires Gradle 8.11.1 or later, and the tests app wrapper was on 8.10, so assembleDebug failed with a version-check error as soon as the AGP pin moved.

Only the tests app is affected. The example apps keep their own lower AGP versions and wrappers.
Independent review found that three of the new failure paths raised Error subtypes into the auth listener. defaultOnAuthError rethrows anything that is not a FirebaseAuthException, and both AuthFlow.onError and the button's handler catch only Exception, so those Errors escaped and left the flow in its loading state permanently.

- AuthAction.none now reports a FirebaseAuthException rather than throwing UnsupportedError out of the tap handler.
- Missing OAuth 1.0a credentials are checked in desktopSignIn, before the base flow reads desktopSignInArgs synchronously, so the ArgumentError is no longer reachable from the UI.
- Empty strings count as missing credentials, since String.fromEnvironment yields an empty string and that is the documented way to supply them. The debug diagnostic no longer fires on them either.
- User cancellation is mapped back to a flow reset. The native SDKs report dismissal as a FirebaseAuthException, which was being rendered as a sign in failure where the previous flow reset silently.
- The linked credential is no longer force unwrapped, since it is nullable on every platform.

Also makes the anonymous upgrade test pass AuthAction.signIn explicitly. The flow resolves to AuthAction.link whenever currentUser is non-null, so the test was passing without the shouldUpgradeAnonymous branch being consulted.
…ale comments

The debug diagnostic told developers to set their Twitter app callback URL to redirectUri when one was supplied, but the native flow on Android and iOS ignores redirectUri and always completes through the Firebase auth handler, so the advice guaranteed failure for exactly the consumers migrating from the custom scheme twitter_login needed. It now names the handler. The desktop flow still honours redirectUri, so its own use of it is unchanged.

Also corrects the class doc, which listed Game Center alongside Apple as exempt from the macOS restriction. Game Center is rejected on every platform, for its own reason, so Apple is the only exception. And removes a comment in the example that lost its subject when the twitter_login dependency was deleted.
… email

The example's sign in handler matched only emailVerified users and unverified users that have an email, so a user with neither matched no case and the screen stayed put after signing in successfully. Twitter only returns an email when the app asks for it, and such a user is never emailVerified, so Twitter sign in landed in that gap.

The app's own initialRoute already treats those users as signed in via its catch all, so this brings the in flow navigation in line with what a relaunch does.
…n signed out

reload() read auth.currentUser! and runs on every app resume, so resuming with no signed in user threw an unhandled TypeError rather than an Exception, which escapes the flow's error handling entirely.

Cancelling an OAuth sign in is the easiest way to hit it: the provider takes the app to the background, cancelling brings it back, and currentUser is still null because the sign in never completed. Any app switch while signed out does the same, so this is not specific to a provider.

The constructor already guards currentUser for null, so this brings reload() in line with the rest of the class rather than changing its contract.
@demolaf
demolaf force-pushed the oauth/twitter-signinwithprovider branch from cc4ae8b to e7c7d62 Compare September 16, 2026 06:52
… found

Device testing surfaced three things the original note could not have covered, because none of them is visible from the source.

- Registering the Android SHA-1 is not sufficient on its own. The certificate hash is embedded in google-services.json at download time, so the file has to be re-downloaded afterwards. The note now carries the error string Firebase shows when either step is missed, since that is what consumers will actually search for.
- Firebase occasionally opens the full browser rather than a Chrome Custom Tab, and abandoning the flow there leaves the operation pending until the app restarts. Recorded as a known limitation, since nothing in the Dart layer can resolve a future the SDK never completes.
- Cancelling returns silently, which is worth stating because it is indistinguishable from nothing having happened.

Also documents that redirectUri is ignored on Android and iOS, which was missing, and splits the section into what you must change, what behaviour changed, and the known limitation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[firebase_ui_oauth_twitter] Replace unmaintained twitter_login dependency

1 participant