You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The Browser plugin opens URLs using SFSafariViewController on iOS and Chrome Custom Tabs on Android. The plugin's own README notes that SFSafariViewController is "compliant with leading OAuth service in-app-browser requirements," and this is broadly true — both primitives do share cookies and session data with the system browser, which satisfies many IdP requirements.
However, they are still not the right tool for structured OAuth/OIDC callback flows, for a different reason: neither primitive provides a way to intercept and return the redirect URI back to the calling app as a resolved value. When an IdP redirects to a custom URL scheme (e.g. myapp://auth/callback?code=...) or a universal link at the end of an auth flow, SFSafariViewController has no mechanism to catch that redirect and return it to the app.
The result is that the browser either stalls on a blank page or the appUrlOpen event fires inconsistently, depending on how the redirect URI is configured. There is no clean, reliable way to close the browser and return the authorization code or token to the calling code as a promise resolution.
That said, it's not impossible to make SSO work in Capacitor, but the proper platform APIs aren't being exposed.
Both platforms provide dedicated APIs designed specifically for this use case, and it would be valuable to expose them through the Browser plugin or as a new dedicated method.
Platform(s)
iOS
Android
Preferred Solution
Expose platform authentication session APIs, either as a new method on the existing Browser plugin or as a separate openAuthSession surface:
This is the current recommended API (available since iOS 12), replacing the deprecated SFAuthenticationSession. It is purpose-built for OAuth and SSO flows: it opens a browser context, monitors for a redirect to the specified callback URL scheme, and returns the full callback URL to the app as a completion handler.
It presents an explicit consent prompt to the user before sharing any cookies with the identity provider session, and supports an prefersEphemeralWebBrowserSession option to use a private, non-shared session instead (which suppresses the consent prompt and is appropriate for flows that don't need SSO cookie persistence).
Android does not have a direct 1:1 equivalent to ASWebAuthenticationSession. The recommended approach is the existing Custom Tabs implementation, but augmented with proper deep link / intent filter handling so the app can receive the OAuth redirect URI when the IdP redirects back. This requires the app to register an intent filter for the callback scheme and the plugin to wire up the round-trip correctly. The AppAuth for Android library documents this pattern well and would be a useful reference implementation.
A minimal API addition could look like:
constresult=awaitBrowser.openAuthSession({url: 'https://idp.example.com/authorize?...',callbackURLScheme: 'myapp',// iOS only: omit to default to shared session with consent promptprefersEphemeralSession: true,});// result.callbackURL contains the full redirect URI the IdP sent back// e.g. "myapp://auth/callback?code=abc123&state=xyz"
On iOS this maps directly to ASWebAuthenticationSession. On Android it would open a Custom Tab and resolve the promise when the app receives the matching intent via the registered deep link.
Alternatives
The @capacitor/community ecosystem has capacitor-app-auth, but it is not officially maintained and tends to lag behind platform API changes.
Manually wiring up App.addListener('appUrlOpen', ...) alongside Browser.open() is a workaround, but it is unreliable — the browser does not close itself when the redirect fires, and sequencing the listener with the browser open/close lifecycle is fragile and error-prone (see Capacitor Browser - Universal link callback not triggered during auth flow #628).
Feature Request
Plugin
@capacitor/browserDescription
The Browser plugin opens URLs using
SFSafariViewControlleron iOS and Chrome Custom Tabs on Android. The plugin's own README notes thatSFSafariViewControlleris "compliant with leading OAuth service in-app-browser requirements," and this is broadly true — both primitives do share cookies and session data with the system browser, which satisfies many IdP requirements.However, they are still not the right tool for structured OAuth/OIDC callback flows, for a different reason: neither primitive provides a way to intercept and return the redirect URI back to the calling app as a resolved value. When an IdP redirects to a custom URL scheme (e.g.
myapp://auth/callback?code=...) or a universal link at the end of an auth flow,SFSafariViewControllerhas no mechanism to catch that redirect and return it to the app.The result is that the browser either stalls on a blank page or the
appUrlOpenevent fires inconsistently, depending on how the redirect URI is configured. There is no clean, reliable way to close the browser and return the authorization code or token to the calling code as a promise resolution.That said, it's not impossible to make SSO work in Capacitor, but the proper platform APIs aren't being exposed.
Both platforms provide dedicated APIs designed specifically for this use case, and it would be valuable to expose them through the Browser plugin or as a new dedicated method.
Platform(s)
Preferred Solution
Expose platform authentication session APIs, either as a new method on the existing Browser plugin or as a separate
openAuthSessionsurface:iOS:
ASWebAuthenticationSessionThis is the current recommended API (available since iOS 12), replacing the deprecated
SFAuthenticationSession. It is purpose-built for OAuth and SSO flows: it opens a browser context, monitors for a redirect to the specified callback URL scheme, and returns the full callback URL to the app as a completion handler.It presents an explicit consent prompt to the user before sharing any cookies with the identity provider session, and supports an
prefersEphemeralWebBrowserSessionoption to use a private, non-shared session instead (which suppresses the consent prompt and is appropriate for flows that don't need SSO cookie persistence).Android: Chrome Custom Tabs + redirect intent handling
Android does not have a direct 1:1 equivalent to
ASWebAuthenticationSession. The recommended approach is the existing Custom Tabs implementation, but augmented with proper deep link / intent filter handling so the app can receive the OAuth redirect URI when the IdP redirects back. This requires the app to register an intent filter for the callback scheme and the plugin to wire up the round-trip correctly. TheAppAuth for Androidlibrary documents this pattern well and would be a useful reference implementation.A minimal API addition could look like:
On iOS this maps directly to
ASWebAuthenticationSession. On Android it would open a Custom Tab and resolve the promise when the app receives the matching intent via the registered deep link.Alternatives
@capacitor/communityecosystem hascapacitor-app-auth, but it is not officially maintained and tends to lag behind platform API changes.App.addListener('appUrlOpen', ...)alongsideBrowser.open()is a workaround, but it is unreliable — the browser does not close itself when the redirect fires, and sequencing the listener with the browser open/close lifecycle is fragile and error-prone (see Capacitor Browser - Universal link callback not triggered during auth flow #628).Additional Context
SFAuthenticationSession(iOS 11 only) is the direct predecessor toASWebAuthenticationSessionand illustrates the intended pattern