Skip to content

feat: web support [#237] - #362

Open
Silfalion wants to merge 21 commits into
clerk-community:mainfrom
Silfalion:feat/web-support
Open

feat: web support [#237]#362
Silfalion wants to merge 21 commits into
clerk-community:mainfrom
Silfalion:feat/web-support

Conversation

@Silfalion

@Silfalion Silfalion commented Mar 10, 2026

Copy link
Copy Markdown

Hi there, saw that we were waiting on the web support so thought I'd make a PR for it, hope this is ok. Summary down below.

Fixes: #237, #302

Depends on: #373

Summary

Add web platform support to the Clerk Flutter SDK.

  • Persistor refactor: Split DefaultPersistor into platform-specific implementations
    (file system on native, localStorage on web) using conditional exports. A separate
    barrel file (clerk_auth_persistor_web.dart) provides the web persistor to web-only
    consumers, since package:web can't be exported from the main library.
  • Caching persistor: Split DefaultCachingPersistor into IO (file-based) and web
    (IndexedDB) implementations with ETag support on both platforms.
  • Widget updates: Replace dart:io usage with universal_io across widgets for
    cross-platform compatibility.
  • Misc: Replace dart:io with universal_io in API, telemetry, and logging internals.
    Remove unused is_web utility files.

Copilot AI review requested due to automatic review settings March 10, 2026 15:40

Copilot AI 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.

Pull request overview

This PR adapts the Clerk Flutter + Dart SDKs to work on web by removing dart:io-based image/file handling, introducing conditional IO/web persistors, and switching image/logo/avatar flows to operate on raw bytes (Uint8List) with web storage via IndexedDB/localStorage.

Changes:

  • Replace File-based image handling with Uint8List across auth APIs and Flutter widgets (use Image.memory).
  • Split persistors into IO vs web implementations via conditional exports; add an IndexedDB-backed file-byte cache on web.
  • Add web-focused dependencies (universal_io, web) and a browser-only test scaffold for the web persistor.

Reviewed changes

Copilot reviewed 36 out of 36 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
packages/clerk_flutter/test/utils/default_caching_persistor_web_test.dart Adds browser-only tests for the web persistor behavior.
packages/clerk_flutter/pubspec.yaml Updates dependencies (adds universal_io/web, changes clerk_auth reference).
packages/clerk_flutter/lib/src/widgets/user/clerk_user_profile.dart Switches profile image update API from File to Uint8List.
packages/clerk_flutter/lib/src/widgets/user/clerk_user_button.dart Switches org creation logo parameter from File to Uint8List.
packages/clerk_flutter/lib/src/widgets/ui/platform_styled_dialog.dart Replaces dart:io platform check with universal_io.
packages/clerk_flutter/lib/src/widgets/ui/editable_profile_data.dart Reads picked images as bytes and passes Uint8List through callbacks.
packages/clerk_flutter/lib/src/widgets/ui/clerk_cached_image.dart Renders cached images from bytes via Image.memory.
packages/clerk_flutter/lib/src/widgets/ui/clerk_avatar.dart Allows avatar override via bytes instead of a File.
packages/clerk_flutter/lib/src/widgets/organization/create_organization_panel.dart Reads logo bytes and uses Image.memory preview.
packages/clerk_flutter/lib/src/widgets/organization/clerk_organization_profile.dart Updates org logo update path to accept Uint8List.
packages/clerk_flutter/lib/src/widgets/organization/clerk_organization_list.dart Wires org creation panel submission to Uint8List logo.
packages/clerk_flutter/lib/src/utils/get_cache_directory.dart Adds conditional export for cache directory getter.
packages/clerk_flutter/lib/src/utils/get_cache_directory_web.dart Web cache directory getter returns null.
packages/clerk_flutter/lib/src/utils/get_cache_directory_io.dart IO cache directory getter uses path_provider.
packages/clerk_flutter/lib/src/utils/default_caching_persistor.dart Adds conditional export for IO vs web caching persistor.
packages/clerk_flutter/lib/src/utils/default_caching_persistor_web.dart Implements web persistor + IndexedDB byte cache and network fetch.
packages/clerk_flutter/lib/src/utils/default_caching_persistor_io.dart Updates IO persistor to cache/stream bytes instead of File.
packages/clerk_flutter/lib/src/utils/clerk_file_cache.dart Changes ClerkFileCache.stream contract to return bytes.
packages/clerk_flutter/lib/src/utils/clerk_auth_config.dart Uses conditional cache-directory getter when constructing default persistor.
packages/clerk_flutter/example/pubspec.yaml Switches example to local path deps for clerk_flutter/clerk_auth.
packages/clerk_flutter/example/macos/Flutter/GeneratedPluginRegistrant.swift Updates generated plugin registration list.
packages/clerk_flutter/example/lib/main.dart Removes exit(1) usage and returns instead (no dart:io).
packages/clerk_auth/pubspec.yaml Adds universal_io/web deps and normalizes quoting.
packages/clerk_auth/lib/src/utils/logging.dart Switches to universal_io and gates stdout.flush() for web.
packages/clerk_auth/lib/src/models/api/api_response.dart Uses universal_io HttpStatus for web compatibility.
packages/clerk_auth/lib/src/clerk_auth/persistor.dart Removes IO-only DefaultPersistor implementation from the shared file.
packages/clerk_auth/lib/src/clerk_auth/persistor_web.dart Adds web DefaultPersistor backed by localStorage.
packages/clerk_auth/lib/src/clerk_auth/persistor_io.dart Adds IO DefaultPersistor backed by filesystem JSON cache.
packages/clerk_auth/lib/src/clerk_auth/persistor_default.dart Adds conditional export to pick IO vs web persistor.
packages/clerk_auth/lib/src/clerk_auth/http_service.dart Removes dart:io dependency (uses pure http).
packages/clerk_auth/lib/src/clerk_auth/auth.dart Updates avatar/logo APIs to accept Uint8List instead of File.
packages/clerk_auth/lib/src/clerk_api/token_cache.dart Uses universal_io for headers/constants.
packages/clerk_auth/lib/src/clerk_api/telemetry.dart Uses universal_io for web-safe IO symbols.
packages/clerk_auth/lib/src/clerk_api/api.dart Switches uploads from File to byte uploads (Uint8List).
packages/clerk_auth/lib/clerk_auth.dart Exports conditional default persistor entry point.
packages/clerk_auth/lib/clerk_auth_persistor_web.dart Adds explicit web-only persistor entry point for web consumers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/clerk_flutter/pubspec.yaml Outdated
Comment thread packages/clerk_flutter/lib/src/utils/clerk_auth_config.dart Outdated
Comment thread packages/clerk_flutter/lib/src/utils/default_caching_persistor_web.dart Outdated
Comment thread packages/clerk_flutter/lib/src/utils/default_caching_persistor_web.dart Outdated
Comment thread packages/clerk_flutter/test/utils/default_caching_persistor_web_test.dart Outdated
Comment thread packages/clerk_flutter/lib/src/utils/clerk_file_cache.dart Outdated
Comment thread packages/clerk_flutter/lib/src/utils/get_cache_directory_web.dart Outdated
Comment thread packages/clerk_auth/lib/src/utils/logging.dart Outdated
Comment thread packages/clerk_auth/lib/src/clerk_api/api.dart
@MarkOSullivan94

Copy link
Copy Markdown
Collaborator

Hey @Silfalion 👋

Thank you for your contribution with this PR.

  1. I've just ran your branch locally and I can see that the Clerk UI is not showing when runningclerk_flutter example on web:
Screenshot 2026-03-23 at 16 03 29
  1. I ran the web version with wasm and it required some changes to get it to run but afterwards the end result was the same as when I ran the dart2js version of the web build the Clerk UI is not displayed

I've pushed these changes to your branch:

6b31a1d
40ab3a4

Make sure you pull the changes before pushing to your branch

@MarkOSullivan94

Copy link
Copy Markdown
Collaborator

I've fixed the merge conflicts after rebasing this branch on top of main

@Silfalion

Copy link
Copy Markdown
Author

Hi @MarkOSullivan94 👋

Thank you as well for taking the time to check it.

The lack of UI is due to the change in dependencies of clerk_auth. The PR works on both packages so clerk_flutter needs to use clerk_auth from the PR instead of the published one.

Regarding this specifically, I should've mentioned a pubspec_overrides.yaml was needed for testing, sorry. Could you check again after adding it, please?

@MarkOSullivan94

MarkOSullivan94 commented Mar 23, 2026

Copy link
Copy Markdown
Collaborator

@Silfalion I've just pushed another two commits, one is to add passkeys-js bundle which is required by passkeys package to work on web.

@MarkOSullivan94
MarkOSullivan94 marked this pull request as draft March 23, 2026 17:34
@Silfalion

Copy link
Copy Markdown
Author

No worries at all! And thank you for the commit.

@MarkOSullivan94

Copy link
Copy Markdown
Collaborator

@Silfalion can you adjust the title and the description of the PR?

The standard we use for the title is something like this:

feat: documentation [#341]

We always do this for the description:

Resolves #341

@Silfalion

Copy link
Copy Markdown
Author

Of course, should I reference this issue?

#237

@MarkOSullivan94

Copy link
Copy Markdown
Collaborator

Of course, should I reference this issue?

#237

Yes please!

Also can you add #373 in the description

@Silfalion Silfalion changed the title Feat/web support feat: web support [#237] Mar 23, 2026
@Silfalion

Copy link
Copy Markdown
Author

Done @MarkOSullivan94 :)

@MarkOSullivan94

Copy link
Copy Markdown
Collaborator

I'm on vacation the rest of the week so further updates will come either from @shinyford or @slightfoot until I return on Monday

@Silfalion

Copy link
Copy Markdown
Author

Sounds good, have a good one!

Comment thread packages/clerk_flutter/lib/src/widgets/ui/clerk_vertical_card.dart

@MarkOSullivan94 MarkOSullivan94 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM 👍

@MarkOSullivan94

Copy link
Copy Markdown
Collaborator

Before merging we should get @slightfoot to review this PR

@slightfoot
slightfoot self-requested a review April 7, 2026 11:18
@slightfoot slightfoot added enhancement New feature or request clerk_auth package: clerk_auth clerk_flutter package: clerk_flutter labels Apr 7, 2026
@artob

artob commented Apr 14, 2026

Copy link
Copy Markdown

@slightfoot @MarkOSullivan94 Any news on this, pretty please?

@MarkOSullivan94

Copy link
Copy Markdown
Collaborator

@slightfoot @MarkOSullivan94 Any news on this, pretty please?

It's awaiting @slightfoot to take a closer look before we can merge this

@kaushiknadig

kaushiknadig commented Jun 25, 2026

Copy link
Copy Markdown

Edit: I am not sure if this comment belongs here in this PR or on this issue: #237

I have left it here for now.

I was trying to get this to work in our application on web. Currently running it through FAPI and manually refreshing the token. So I thought even if not merged, let me try it out. So i checkout clerk_auth to this branch and added it to flutter and tried it.

I was able to sign in. Even for sign in, I had to use an extended http class to override some headers.
Converted is_native to false, and then I had to strip out some headers as well. After that I was able to get signin to work. However after sign in, the clerk session cookie was not being set directly to the cookies section. Because of this I was not able to call the refresh token.

I asked AI to reformat this wrt my code, here is what it said.

We’ve been trying to use clerk_auth in a Flutter web app and ran into several issues that go beyond what this PR and #395 address, so I’m documenting them here for proper web support.


Issues observed on Flutter web

1. Token refresh is broken on web

TokenCache.canRefreshSessionToken requires hasClientToken, and that is only set from the Authorization response header (token_cache.dart, line 152). In browser mode (_is_native=false), FAPI does not send that header, so hasClientToken stays false permanently.

As a result, _pollForSessionToken silently does nothing every 53 seconds, the session JWT expires, and the backend starts returning 401.

2. _is_native=true is incompatible with browsers - Which could be intentional.

Browsers automatically include the Origin header on cross-origin requests. FAPI returns a 400 if both Origin and Authorization are present:

"For security purposes, only one of the Origin and Authorization headers should be provided".

That means native mode is blocked by the browser’s own CORS behavior.

3. FAPI never sets the __client cookie on web

Even with _is_native=false, Clerk’s FAPI does not set a __client cookie in the response. We verified this in DevTools: only Cloudflare cookies are present after sign-in.

That leaves no cookie to send on subsequent requests, so cookie-based auth — the standard browser path — is unavailable.

4. Session restore on reload fails

Because no __client cookie is set and TokenCache has no persisted client token in browser mode, clerkAuth.initialize() cannot restore the session on page reload.

isSignedIn returns false even if the user was signed in moments ago.


What the JS SDK does differently

The @clerk/clerk-js SDK uses AuthCookieService plus SessionCookiePoller, polling every 5 seconds via session.getToken() using a first-party session cookie set at the subdomain level, such as clerk.yourdomain.com.

The Flutter SDK currently has no equivalent cookie-based auth path.


What’s needed for proper Flutter web support

  • Either: FAPI must set the __client cookie when _is_native=false is sent from a browser origin, with SameSite=None; Secure for cross-subdomain use, and TokenCache must extract the auth credential from the cookie or response body rather than only the Authorization response header.
  • Or: the SDK needs a separate web auth flow that mirrors what clerk-js does, with cookie-based polling and no dependency on the Authorization header.

Happy to elaborate or test any proposed fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clerk_auth package: clerk_auth clerk_flutter package: clerk_flutter enhancement New feature or request web A task related to web

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Web Platform Support to clerk_auth Dart Library

8 participants