Skip to content

feat(oidc_android,oidc_ios)!: first-party native auth, drop flutter_appauth [WIP]#315

Draft
ahmednfwela wants to merge 10 commits into
mainfrom
feat/native-channel-auth
Draft

feat(oidc_android,oidc_ios)!: first-party native auth, drop flutter_appauth [WIP]#315
ahmednfwela wants to merge 10 commits into
mainfrom
feat/native-channel-auth

Conversation

@ahmednfwela
Copy link
Copy Markdown
Member

Implements the native authorization / end-session browser flow directly in the existing platform packages (no shared mixin, no new package, per maintainer direction), replacing flutter_appauth with first-party code. All OIDC logic (URL building, PKCE, state, nonce, response parsing) stays in pure-Dart oidc_core (request.generateUri() + OidcEndpoints.parseAuthorizeResponse()), so PKCE/state/nonce are identical on every platform.

Status

  • Android (oidc_android): OidcAndroid implements OidcPlatform directly; native OidcPlugin.kt uses Chrome Custom Tabs (androidx.browser:browser:1.10.0) + redirect capture + cancellation; flutter_appauth/oidc_flutter_appauth deps removed; README documents the redirect intent-filter. Dart verified: analyze clean, 5/5 mock-channel tests.
  • iOS (oidc_ios): in progress — ASWebAuthenticationSession.
  • macOS: shares the Apple code (follow-up).
  • Example-app manifests (Android intent-filter / iOS URL scheme) for integration E2E.

Not verifiable locally (needs this CI / a device)

Native Kotlin/Swift compilation and on-device E2E — that is exactly what the draft CI run will exercise. Expect the native integration jobs to be the iteration surface.

Roadmap: #205 (remove flutter_appauth). De-risks #76, #118, #128, #130, #174, #213, #281, #309.

🤖 Generated with Claude Code

ahmednfwela and others added 2 commits May 29, 2026 18:07
…Tabs auth

Implements the Android authorization/end-session browser flow directly in oidc_android using Chrome Custom Tabs (androidx.browser 1.10.0) instead of flutter_appauth/AppAuth-Android. The native side only opens the URL and returns the captured redirect URI; ALL OIDC logic (URL building, PKCE, state, nonce, parsing) stays in pure-Dart oidc_core via request.generateUri() + OidcEndpoints.parseAuthorizeResponse(). PKCE is now consistent across platforms (no native AppAuth-generated verifier).

OidcAndroid implements OidcPlatform directly (no shared mixin, no new package). Native OidcPlugin.kt: Custom Tabs + redirect capture via onNewIntent + cancellation via Activity lifecycle, with an ACTION_VIEW fallback. Drops flutter_appauth + oidc_flutter_appauth deps. Pure-Kotlin/AAR => no .so (16 KB page-size compliant). README documents the redirect intent-filter + taskAffinity pitfall.

Dart verified: analyze clean, 5/5 mock-channel unit tests pass. NOTE: native compilation + on-device E2E still need CI/a device. Relates to #205, #76, #118, #128, #174, #281.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 29, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 227457b7-3193-4fb6-aab7-77d910d9e60c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/native-channel-auth

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

ahmednfwela and others added 4 commits May 29, 2026 18:15
…ticationSession

Implements the iOS authorization/end-session browser flow directly in oidc_ios using ASWebAuthenticationSession (AuthenticationServices) instead of flutter_appauth/AppAuth-iOS. Native side only opens the URL and returns the redirect URI; all OIDC logic stays in oidc_core.

OidcIOS implements OidcPlatform directly (no shared mixin). Native OidcPlugin.swift: ASWebAuthenticationSession + presentationContextProvider held strongly to avoid the #213 EXC_BAD_ACCESS, UIWindowScene anchor (UIScene default on Flutter 3.44), prefersEphemeralWebBrowserSession from the ios option, and error mapping (canceledLogin->USER_CANCELLED, presentationContext*->PRESENTATION_CONTEXT_INVALID handled as the #211 iOS+Azure "-3" logout case). Drops flutter_appauth + flutter_appauth_platform_interface + oidc_flutter_appauth. Bumps iOS deployment target to 13.0 (podspec + Package.swift); SwiftPM already enabled (#309).

Dart verified: analyze clean, 6/6 mock-channel tests pass. NOTE: native compilation + on-device E2E still need CI/a device. Relates to #205; de-risks #211, #213, #309, #124.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ine setup

Implements the sourced cross-check findings on the first-party native auth.

iOS (OidcPlugin.swift):
- Route every FlutterResult through a main-thread reply() helper —
  ASWebAuthenticationSession's completion handler carries no documented
  thread guarantee, and Flutter requires replies on the platform thread.
- Resolve each flow exactly once via pendingResult; supersede any in-flight
  session (its Future is resolved as cancelled) instead of leaking it.
- Adopt init(url:callback:) on iOS 17.4+ (.customScheme/.https) to silence the
  deprecation and unlock Universal-Link redirects; keep callbackURLScheme init
  below 17.4.
- Robust presentation-anchor fallback; preserve numeric error code in details.

Android — simplify intent filters (closes #174 root cause):
- Ship a plugin-owned, transparent OidcRedirectActivity whose intent-filter
  scheme is driven by a single ${oidcRedirectScheme} manifest placeholder
  (default provided in the library build.gradle). Consumers set ONE gradle
  line and add NO <intent-filter>/launchMode/taskAffinity to MainActivity.
- OidcPlugin delivers the captured redirect in-memory via a static dispatcher
  (no NewIntentListener on the host); keeps lifecycle-based cancel detection.
  Uses the app's default task affinity so finishing returns to the host task
  (the proven flutter_web_auth_2 CallbackActivity approach).
- Narrow the launch fallback to ActivityNotFoundException (launchUrl already
  falls back to the default browser).
- Update example to the one-line oidcRedirectScheme; drop dead
  appAuthRedirectScheme; rewrite oidc_android README.

Cross-cutting:
- Domain-prefix channel names (com.bdayadev.oidc/android,/ios) per Flutter's
  uniqueness convention; native + Dart kept in lockstep.
- Catch MissingPluginException in both _authenticate() and surface a clear
  OidcException.
- Extract channel/method/error-code magic strings to shared
  OidcNativeChannels/OidcNativeMethods/OidcNativeErrorCodes in
  oidc_platform_interface (single source of truth).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tup docs

- oidc_android/oidc_ios tests: assert the domain-prefixed channel name matches
  the shared constant, and that a missing native plugin surfaces a clear
  OidcException (both suites green: 7 + 8 tests).
- docs/oidc-getting-started.md: rewrite Android to the one-line oidcRedirectScheme
  placeholder (drop the dead appAuthRedirectScheme + AppAuth link, add the
  upgrade + App Links notes); split "iOS/macOS" into iOS (first-party
  ASWebAuthenticationSession, no Info.plist URL scheme, iOS 13+) and macOS
  (still AppAuth, keeps CFBundleURLSchemes).
- docs/index.md + oidc_ios/README.md: correct the per-platform mechanism
  (Android Custom Tabs, iOS ASWebAuthenticationSession, macOS-only appauth),
  add the oidc_ios redirect/setup section, https->badge fixes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gitguardian
Copy link
Copy Markdown

gitguardian Bot commented May 29, 2026

⚠️ GitGuardian has uncovered 9 secrets following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secrets in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
8133728 Triggered Elliptic Curve Private Key c3a364b packages/x509_plus/test/files/ec256.key View secret
8133786 Triggered Generic Private Key c3a364b packages/jose_plus/test/pem/rsa.key View secret
8133732 Triggered Elliptic Curve Private Key c3a364b packages/x509_plus/test/files/ec256k.key View secret
8133787 Triggered Elliptic Curve Private Key c3a364b packages/jose_plus/test/pem/ec256k.key View secret
8133729 Triggered Elliptic Curve Private Key c3a364b packages/x509_plus/test/files/ec521.private.key View secret
8133726 Triggered Elliptic Curve Private Key c3a364b packages/x509_plus/test/files/ec384.private.key View secret
8133785 Triggered Elliptic Curve Private Key c3a364b packages/jose_plus/test/pem/ec256.key View secret
8133784 Triggered RSA Private Key c3a364b packages/jose_plus/example/jwtRS512.key View secret
8133733 Triggered Elliptic Curve Private Key c3a364b packages/x509_plus/test/files/ec384.key View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secrets safely. Learn here the best practices.
  3. Revoke and rotate these secrets.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 29, 2026

Visit the preview URL for this PR (updated for commit f158c4e):

https://oidc-flutter-docs--pr-315-docs-pk5pwocy.web.app

(expires Sat, 06 Jun 2026 03:23:24 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: be73cc36b5cf3e9d187cedf949ae5b2218b855cd

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 29, 2026

Visit the preview URL for this PR (updated for commit f158c4e):

https://oidc-flutter-example--pr-315-example-zu4669ju.web.app

(expires Sat, 06 Jun 2026 03:23:34 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: 5ca8b925ef0acd3a0c8fced26fcc6d1bfac11b49

ahmednfwela and others added 4 commits May 30, 2026 00:27
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…droid build

Verified against the live Flutter SwiftPM-for-plugin-authors doc (Flutter 3.44):
swiftPackageManager:true is CORRECT current syntax (kept); the real gaps were
the file layout + FlutterFramework dependency ("New in Flutter 3.41").

SwiftPM migration (oidc_ios + oidc_macos):
- Move Package.swift to ios/<plugin>/Package.swift, macos/<plugin>/Package.swift.
- Move Swift sources into <platform>/<plugin>/Sources/<plugin>/ (history kept).
- Add the FlutterFramework package + product dependency to Package.swift.
- Update podspec source_files to the new Sources/ path; fix placeholder
  homepage/author metadata.
- macOS deployment target standardized to 10.15 (Package.swift + podspec).
- Raise oidc_ios/oidc_macos/oidc pubspec floor to sdk ^3.11 / flutter >=3.41
  (required by FlutterFramework SPM support).

Conformance (safe items):
- Domain-prefix the macOS/Windows/Linux stub channels
  (com.bdayadev.oidc/{macos,windows,linux}).
- .gitignore: add SPM artifacts (.build/, .swiftpm/).
- Document macOS App Sandbox network.client entitlement (oidc_macos README +
  getting-started); note iOS needs none.

Fix Android example build (regression from dropping appAuthRedirectScheme):
flutter_appauth is still pulled in transitively via oidc_macos, and its Android
manifest requires ${appAuthRedirectScheme}. Restore it as a DISTINCT unused
scheme so AppAuth's receiver can't collide with the first-party
OidcRedirectActivity redirect; document the transitive requirement (goes away
once macOS migrates to a first-party impl).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…er_appauth

Completes the flutter_appauth removal: macOS now uses the system
ASWebAuthenticationSession directly (same first-party approach as iOS), so
`flutter_appauth` is no longer a dependency of ANY endorsed platform.

- oidc_macos native: full ASWebAuthenticationSession OidcPlugin (mirrors iOS;
  AppKit NSWindow presentation anchor instead of UIKit; main-thread reply,
  single-resolution pendingResult, in-flight supersede, error mapping).
- oidc_macos Dart: channel-based OidcMacOS over com.bdayadev.oidc/macos,
  mirroring the iOS contract (MissingPluginException handling, USER_CANCELLED ->
  null, preferEphemeral from options.macos). Removes the OidcFlutterAppauth
  mixin.
- oidc_macos pubspec: drop flutter_appauth ^11 + oidc_flutter_appauth deps.
- Shared constant OidcNativeChannels.macos; channel-contract tests (7/7 green).

Payoff — flutter_appauth fully leaves the consumer tree (verified: the example
app registers zero appauth plugins on any platform), so:
- Revert the Android example to the true one-line oidcRedirectScheme setup (the
  transitive appAuthRedirectScheme requirement is gone).
- macOS getting-started/README rewritten to first-party (no CFBundleURLSchemes;
  scheme registered at runtime; macOS 10.15+; App Sandbox network.client kept).
- index.md: all six platforms first-party; oidc_flutter_appauth now optional.

oidc_flutter_appauth remains published for users who specifically want an
AppAuth-based flow, but nothing depends on it by default.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The SwiftPM migration raised the package floor to Flutter >=3.41 / Dart 3.11
(FlutterFramework in Package.swift), but CI's integration actions pinned Flutter
3.35.4 — so `pub get`/bootstrap failed at "Set up Environment" on every
platform job. And unit_tests (latest stable, Dart 3.12) failed format because 5
files were still in the pre-3.12 formatter style.

- .github/actions/flutter_base + integration_test_base: pinned Flutter
  3.35.4 -> 3.44.0 (matches dev; satisfies the >=3.41 floor). unit_tests keeps
  floating latest stable/beta.
- Root workspace pubspec: flutter >=3.35 -> >=3.41, sdk ^3.9 -> ^3.11.
- dart format (Dart 3.12) the 5 straggler files
  (oidc.dart, facade.dart, user_manager.dart, test/mock_client.dart,
  test/oidc_test.dart); whole repo now format-clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant