OAuth uses SFSafariViewController or Custom Tabs, not embedded WebView
Why it matters
An embedded WebView used for OAuth credential entry violates Apple's guideline 5.1.1 and the OAuth 2.0 security model: the app can read the WebView's DOM content, giving it access to the user's credentials on the OAuth provider's login page. CWE-522 (insufficiently protected credentials) applies directly. Google, Apple, and GitHub explicitly prohibit embedded WebView OAuth because it enables phishing — an app can silently capture the username and password typed into what appears to be Google's login form. The correct implementations (SFSafariViewController, AuthenticationSession, Chrome Custom Tabs) operate in a separate process the app cannot read.
Severity rationale
Low because the pattern requires an OAuth flow to be present and is not an immediate binary rejection in all cases, but Apple has started rejecting it more consistently under guideline 5.1.1.
Remediation
Replace any WebView OAuth flow with expo-auth-session, which uses SFSafariViewController on iOS and Chrome Custom Tabs on Android.
// src/screens/LoginScreen.tsx
import * as Google from 'expo-auth-session/providers/google';
export default function LoginScreen() {
const [request, response, promptAsync] = Google.useAuthRequest({
clientId: process.env.EXPO_PUBLIC_GOOGLE_CLIENT_ID,
});
useEffect(() => {
if (response?.type === 'success') {
const { authentication } = response;
// exchange authentication.accessToken for your session
}
}, [response]);
return <Button title="Sign in with Google" onPress={() => promptAsync()} />;
}
For Apple Sign In (required when offering any third-party sign-in on iOS), use expo-apple-authentication. Never use a <WebView source={{ uri: 'https://accounts.google.com/...' }} /> for credential entry.
Detection
- ID:
webview-oauth-secure - Severity:
low - What to look for: Count all relevant instances and enumerate each. Search for OAuth flows in the codebase. Look for
WebViewcomponents used for authentication (check props likesource={{ uri: 'https://accounts.google.com/...' }}or similar OAuth provider URLs in WebView). The correct pattern is:expo-auth-session(Expo),react-native-app-auth(React Native),SFSafariViewController(iOS native),Chrome Custom Tabs(Android). Look forWebViewimports in authentication-related files:src/screens/auth/,src/components/auth/, login flows. Check if the WebView has access to the user's session cookies (which would allow the app to read OAuth tokens from the page content). - Pass criteria: OAuth authentication flows use system browser components (
SFSafariViewController/AuthenticationSessionon iOS,Chrome Custom Tabson Android) or well-established auth libraries (expo-auth-session,react-native-app-auth). At least 1 implementation must be verified. No embedded WebView is used for OAuth credential entry. - Fail criteria: OAuth flow embeds a
WebViewcomponent that loads an OAuth provider's login page (Google, Apple, Facebook, GitHub, etc.) — this allows the app to read the WebView's content, which is a security violation. - Skip (N/A) when: App has no web-based OAuth authentication (uses only email/password, phone number, or anonymous auth without web OAuth providers).
- Detail on fail:
"Google OAuth is implemented with an embedded WebView loading accounts.google.com — use expo-auth-session or react-native-app-auth instead" - Remediation: Apple guideline 5.1.1 prohibits capturing user credentials from OAuth provider sites via WebView.
- Replace embedded WebView OAuth with
expo-auth-session:import * as Google from 'expo-auth-session/providers/google'; const [request, response, promptAsync] = Google.useAuthRequest({ ... }); - Or use
react-native-app-authfor non-Expo projects - For Apple Sign In, use
expo-apple-authenticationor theAuthenticationServicesframework directly — this is required for any app offering third-party sign-in on iOS
- Replace embedded WebView OAuth with
External references
- cwe · CWE-522 — Insufficiently Protected Credentials
- external · apple-guideline-5.1.1-oauth-webview — Apple App Store Review Guideline 5.1.1 — OAuth Must Use System Browser, Not Embedded WebView
Taxons
History
- 2026-04-18·v1.0.0·Initial import from app-store-review-blockers·automated