Skip to content

fix(flutter): sign in with OAuth2 on Windows and Linux through a loopback token callback - #2093

Merged
ChiragAgg5k merged 1 commit into
mainfrom
fix/flutter-desktop-oauth
Oct 17, 2026
Merged

ChiragAgg5k merged 1 commit into
mainfrom
fix/flutter-desktop-oauth

Conversation

@ChiragAgg5k

@ChiragAgg5k ChiragAgg5k commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

What does this PR do?

OAuth2 sign-in from the Flutter SDK could not work on Windows or Linux.

  • With no success URL, webAuth passed appwrite-callback-<projectId> as the callback. On Windows and Linux, flutter_web_auth_2 (5.1, useWebview: false) runs a local HTTP server and rejects anything that is not http://localhost:{port} (Callback url scheme must start with http://localhost:{port}).
  • With a localhost success URL, the browser did come back, but createOAuth2Session only adds key and secret to the redirect when it lands on the server's own default success page (app/controllers/api/account.php, the $state['success']['host'] === $consoleHostname && path === $oauthDefaultSuccess branch). Any other success URL gets cookies set in the browser only, so the SDK threw Invalid OAuth2 Response. Key and Secret not available.

The token flow has no such restriction: createOAuth2Token redirects to any allowed success URL with userId and secret, and createSession(userId, secret) turns that into a session. No server change is needed.

On Windows and Linux, webAuth now:

  • uses the given success URL as the loopback callback, or binds a free loopback port and uses http://localhost:<port>/ when none is given;
  • sets success to that callback, and failure too unless one was given, so errors come back to the app instead of leaving the listener waiting for its timeout;
  • for createOAuth2Session, opens /account/tokens/oauth2/{provider} instead and exchanges the returned userId and secret with POST /account/sessions/token, which stores the session cookie like any other sign-in.

Android, iOS and macOS keep the appwrite-callback-<projectId> flow. While there, saving that session now waits for an init() that is already in flight (it used to call init(), which returns at once in that case, leaving _cookieJar unset) and awaits the cookie write.

The project still needs a Web platform for localhost (any port matches) so the server accepts the loopback success URL.

Test Plan

New test/src/client_io_test.dart in the generated Flutter SDK (run by flutter test in validation). It mocks the flutter_web_auth_2 and path_provider channels, points the client at a local HttpServer, and overrides defaultTargetPlatform:

  • Linux and Windows, no success URL: the callback is http://localhost:<port>/, the URL opened is the token endpoint with success/failure set and scopes[] kept, the client posts {"userId","secret"} to /v1/account/sessions/token, and the session cookie is stored.
  • Linux and Windows, success and failure given: both are kept and used as the callback.
  • Linux and Windows, error callback: throws the parsed exception and makes no request.
  • Android: callback is appwrite-callback-project, URL unchanged, the session cookie from key/secret is stored.

Red/green: generated with the main client_io.dart.twig, 5 of 7 fail (both loopback sign-in cases and both success/failure cases on each desktop platform, plus Android with LateInitializationError: Field '_cookieJar' has not been initialized). With this branch all 7 pass, and the full SDK suite passes (+523 ~1) four runs in a row.

Also run: dart format --output=none --set-exit-if-changed on the changed files, composer lint-twig, composer refactor:check, composer lint, max-line-length.sh . 1200 "*.twig", and the Generation suite.

Related PRs and Issues

Closes #2094

…back token callback

flutter_web_auth_2 only accepts an http://localhost:{port} callback on Windows and Linux, so the appwrite-callback scheme failed outright. A localhost success URL got past that, but the server only adds key and secret to its own default success page, so the session could never reach the app. The token flow returns userId and secret to any allowed success URL, so desktop now opens the token endpoint on a loopback callback (a free port when no success URL is given) and exchanges the result with createSession.

Saving the mobile session also waited on init() without waiting for an init already in flight, and did not await the cookie write.
@hansi-codes

hansi-codes Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

🟢 Tier S · Ready to merge

This change adds a loopback callback and token-to-session exchange for Flutter OAuth sign-in on Windows and Linux, while retaining the existing callback flow on mobile platforms. It also makes session initialization and cookie persistence awaitable, and registers tests for the new platform-specific behavior.

Verdict New comments Fixed Still open
✅ Approved 0 0 0
📂 Walkthrough · 3
File Change
src/SDK/Language/Flutter.php Registers the generated Flutter client I/O OAuth test.
templates/flutter/lib/src/client_io.dart.twig Adds desktop loopback OAuth callbacks, token session exchange, and awaited cookie initialization.
templates/flutter/test/src/client_io_test.dart.twig Covers desktop OAuth callbacks and exchange, errors, and Android session cookie persistence.

Reviewed b16fb7c · Details · Comment @hansi-codes review to re-run, or mention @hansi-codes with a question.

@hansi-codes hansi-codes 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.

🟢 Tier S · Looks good to merge. Summary

@ChiragAgg5k
ChiragAgg5k merged commit 49681d1 into main Oct 17, 2026
61 checks passed
@ChiragAgg5k
ChiragAgg5k deleted the fix/flutter-desktop-oauth branch October 17, 2026 10:03
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.

Sign in with OAuth2 on Windows and Linux through a loopback token callback in the Flutter SDK

1 participant