Skip to content

feat(android): optional Custom Tabs for oauth2 (#442) - #443

Merged
riderx merged 3 commits into
mainfrom
fix/android-oauth2-custom-tabs
Aug 11, 2026
Merged

feat(android): optional Custom Tabs for oauth2 (#442)#443
riderx merged 3 commits into
mainfrom
fix/android-oauth2-custom-tabs

Conversation

@riderx

@riderx riderx commented Aug 11, 2026

Copy link
Copy Markdown
Member

What

  • Add optional androidUseCustomTabs on OAuth2ProviderConfig (default false)
  • When enabled, Android oauth2 login uses Chrome Custom Tabs + deep-link callback instead of embedded WebView
  • Document the option in README and Keycloak setup docs

Why

How

  • Reuse the same Custom Tabs + handleOnNewIntent pattern already used by openSecureWindow()
  • WebView path unchanged when the flag is unset/false
  • Cancel on resume without redirect (same as openSecureWindow)

Testing

  • bun run build
  • bun run verify:android

Not Tested

  • Device/emulator login against Keycloak → Entra with Custom Tabs enabled
  • Intent-filter / App Link redirect round-trip on a real app

Made with Cursor


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added optional Android Chrome Custom Tabs support for OAuth2 authentication.
    • Added deep-link and App Link redirect handling, including redirects received during app startup.
    • Authentication now restores interrupted login state and handles cancellation when returning without completing authorization.
    • Added the androidUseCustomTabs configuration option, disabled by default.
  • Documentation

    • Updated setup guidance with Custom Tabs configuration, redirect requirements, Android manifest intent filters, and activity launch modes.

Add androidUseCustomTabs (default false) so apps can opt into Chrome Custom Tabs instead of the embedded WebView, without breaking existing WebView flows.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

Copy link
Copy Markdown
Contributor

Beta npm build

Maintainers can publish this PR to npm for fast testing.

Comment /publish-beta after the PR checks are green.

The workflow will:

  • publish a prerelease package on the beta tag
  • add a pinned pr-443 dist-tag for this exact PR build
  • update this comment with the install command

Security note: beta publish is only enabled for branches inside this repository.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 40 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2dc929d1-741e-4dc8-9313-a4e4de7afe22

📥 Commits

Reviewing files that changed from the base of the PR and between 9adef08 and 421a800.

📒 Files selected for processing (1)
  • android/src/main/java/ee/forgr/capacitor/social/login/SocialLoginPlugin.java
📝 Walkthrough

Walkthrough

The Android OAuth2 provider now supports optional Chrome Custom Tabs authorization. It persists pending login state, handles deep-link and App Link redirects, supports process recovery, detects cancellation on resume, and documents the required configuration.

Changes

Android Custom Tabs OAuth2

Layer / File(s) Summary
Custom Tabs configuration contract
src/definitions.ts, android/src/main/java/.../OAuth2Provider.java, README.md, docs/setup_keycloak.md
Adds the androidUseCustomTabs option with a default of false. Preserves the option through provider initialization and discovery. Documents redirect, manifest, and activity launch requirements.
Custom Tabs authorization and callback flow
android/src/main/java/.../OAuth2Provider.java
Launches authorization in Chrome Custom Tabs when enabled and falls back to WebView when unavailable. Persists pending state, validates redirects, supports token exchange after process death, handles cancellation, and clears Custom Tabs state.
Activity lifecycle redirect wiring
android/src/main/java/.../SocialLoginPlugin.java
Buffers redirects received before OAuth2 initialization, replays them after initialization, and forwards resume and new-intent events to the OAuth2 provider.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant OAuth2Provider
  participant ChromeCustomTabs
  participant SocialLoginPlugin
  OAuth2Provider->>ChromeCustomTabs: Open authorization URL
  ChromeCustomTabs->>SocialLoginPlugin: Deliver redirect URI
  SocialLoginPlugin->>OAuth2Provider: Process redirect URI
  OAuth2Provider->>OAuth2Provider: Exchange code or cancel pending login
Loading

Suggested reviewers: wcaleniewolny

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the Android Custom Tabs feature for OAuth2.
Linked Issues check ✅ Passed The changes implement optional Android Custom Tabs, WebView fallback, redirect handling, state persistence, cancellation, and required documentation for issue #442.
Out of Scope Changes check ✅ Passed The code, configuration, redirect handling, state management, and documentation changes directly support the linked issue objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@cursor
cursor Bot requested a review from WcaleNieWolny August 11, 2026 11:14

@cursor cursor 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.

Risk: high. Left a non-blocking comment because this PR changes Android OAuth2 login (Custom Tabs path) and exceeds the low-risk auto-approval threshold. Cursor Bugbot was not present; human review is needed and a reviewer was assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Approver External

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@android/src/main/java/ee/forgr/capacitor/social/login/OAuth2Provider.java`:
- Around line 710-738: Update handleRedirectUri to validate the redirect URI by
components instead of using redirectUrl.startsWith(uri.toString()). Require
matching scheme, authority, and exact path between pendingState.redirectUri and
uri, while preserving the existing rejection behavior for invalid or mismatched
redirects before processCallbackData is called.
- Around line 496-503: Update the Custom Tabs launch flow around
launchCustomTabs and its caller to catch ActivityNotFoundException, reject the
pending call, and invoke cleanupPending(). When falling back to
OAuth2LoginActivity after this failure, clear pendingUseCustomTabs before
starting the fallback activity.

In
`@android/src/main/java/ee/forgr/capacitor/social/login/SocialLoginPlugin.java`:
- Around line 625-631: Update SocialLoginPlugin’s redirect handling and
initialize flow to buffer an initial ACTION_VIEW URI when the OAuth2 provider is
unavailable, then replay it after OAuth2Provider initialization. Persist and
restore pendingCall, pendingState, pendingUseCustomTabs, and the buffered
callback across process recreation, and ensure the transaction state is cleared
only after login resolves or rejects; apply the corresponding OAuth2Provider
handling changes at OAuth2Provider.java lines 58-60.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3421978c-26dd-4e0f-b5b6-c18e9900f3a4

📥 Commits

Reviewing files that changed from the base of the PR and between abdfe8f and 387f218.

📒 Files selected for processing (5)
  • README.md
  • android/src/main/java/ee/forgr/capacitor/social/login/OAuth2Provider.java
  • android/src/main/java/ee/forgr/capacitor/social/login/SocialLoginPlugin.java
  • docs/setup_keycloak.md
  • src/definitions.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual)

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 5 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread android/src/main/java/ee/forgr/capacitor/social/login/OAuth2Provider.java Outdated
Comment thread android/src/main/java/ee/forgr/capacitor/social/login/OAuth2Provider.java Outdated
Comment thread android/src/main/java/ee/forgr/capacitor/social/login/OAuth2Provider.java Outdated
Comment thread docs/setup_keycloak.md Outdated
Catch missing-browser launches with WebView fallback, match redirects by URI components, parse encoded fragments, persist/replay Custom Tabs PKCE state across process death, and document launchMode.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@android/src/main/java/ee/forgr/capacitor/social/login/SocialLoginPlugin.java`:
- Around line 187-192: In the provider-registration flow around
handleOnResume(), restore the pending Custom Tabs session from the stored
CUSTOM_TABS_PENDING_* state after registration, then call
handleUserReturnedWithoutCallback() when no buffered redirect was handled so the
orphaned transaction is canceled and storage is cleared. Preserve the existing
pendingOAuth2RedirectUri replay behavior when a redirect is available.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: fdf1b035-3289-4387-aed8-10d70bf905d9

📥 Commits

Reviewing files that changed from the base of the PR and between 387f218 and 9adef08.

📒 Files selected for processing (4)
  • README.md
  • android/src/main/java/ee/forgr/capacitor/social/login/OAuth2Provider.java
  • android/src/main/java/ee/forgr/capacitor/social/login/SocialLoginPlugin.java
  • docs/setup_keycloak.md
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual)

If resume ran before initialize with no buffered redirect, restore persisted PKCE state and cancel/clear the orphaned Custom Tabs transaction.

Co-authored-by: Cursor <cursoragent@cursor.com>

@cursor cursor 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.

{
  "review_module": "filesystem_workspace_boundary",
  "result": "pass",
  "summary": "No filesystem workspace-boundary vulnerabilities found in changed lines.",
  "findings": [],
  "validated_changed_files": [
    "README.md",
    "android/src/main/java/ee/forgr/capacitor/social/login/OAuth2Provider.java",
    "android/src/main/java/ee/forgr/capacitor/social/login/SocialLoginPlugin.java",
    "docs/setup_keycloak.md",
    "src/definitions.ts"
  ],
  "notes": "Reviewed only the PR diff hunks. Changes introduce OAuth Custom Tabs/deep-link state handling and documentation updates; no new model-controlled filesystem path inputs, workspace containment checks, cache/tarball/git/project/canvas path joins, or symlink validation logic were added in the modified lines."
}
Open in Web View Automation 

Sent by Cursor Security Agent: Security Reviewer

@riderx
riderx merged commit 8f7dadb into main Aug 11, 2026
12 checks passed
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.

Generic OAuth2 provider uses an embedded WebView on Android instead of Custom Tabs

1 participant