Why Native Apps Need Special OAuth Handling
Web apps handle OAuth simply: redirect to provider → user authenticates → redirect back with tokens. But native apps face challenges:| Challenge | Why it matters |
|---|---|
| No browser address bar | Users can’t verify they’re on the real provider’s site (phishing risk) |
| WebView restrictions | Google and Apple block OAuth in embedded WebViews for security |
| App Store requirements | iOS and Android require secure browser sessions for OAuth |
| Session isolation | Tokens obtained in a browser session can’t automatically transfer to the app |
- iOS: ASWebAuthenticationSession
- Android: Chrome Custom Tabs
The Two Despia URL Protocols
Despia’s OAuth mechanism relies on just two URL protocols: Everything else is standard OAuth. Despia doesn’t modify the OAuth protocol - it just provides secure transport.The Universal OAuth Flow
Key Concepts
1. The Callback URL Split
In standard web OAuth, the callback URL is a single endpoint. In Despia, you need two callback paths:2. State Preservation
The OAuthstate parameter serves double duty:
- CSRF protection (standard OAuth)
- Deeplink scheme (Despia-specific)
3. Token Handoff
The secure browser and your WebView are isolated. Tokens obtained in the browser cannot be directly accessed by your app. The handoff happens via URL:4. The oauth/ Prefix Requirement
Theoauth/ segment in the deeplink is not just a path - it’s a signal to Despia:
| Deeplink | Result |
|---|---|
myapp://oauth/auth?token=xxx | ✓ Browser closes, app receives /auth?token=xxx |
myapp://oauth/home | ✓ Browser closes, app receives /home |
myapp://oauth/callback?foo=bar | ✓ Browser closes, app receives /callback?foo=bar |
myapp://auth?token=xxx | ✗ Browser stays open (user stuck) |
myapp://home | ✗ Browser stays open (user stuck) |
Provider-Specific Considerations
While the Despia mechanism is universal, providers have quirks:Implicit vs Authorization Code Flow
| Flow | How tokens arrive | Used by |
|---|---|---|
| Implicit | URL fragment (#access_token=xxx) | Supabase/Google (legacy) |
| Authorization Code | Query param (?code=xxx) | Most modern OAuth |
/native-callback page must handle both:
Apple Sign In Differences
Apple has platform-specific behavior:| Platform | Best approach |
|---|---|
| iOS | Apple JS SDK → Native Face ID dialog (no browser needed) |
| Android | oauth:// protocol → ASWebAuthenticationSession |
| Web | Apple JS SDK → Browser dialog |
oauth:// flow entirely and use Apple’s native dialog for instant authentication.
Response Mode: form_post
Some providers (Apple on Android) useresponse_mode=form_post, which POSTs data to your backend instead of redirecting. Your backend then redirects to the deeplink:
Integration with User Session System
OAuth provides authentication. The Despia User Session system provides identity persistence. They work together: The key integration point is the login endpoint:app_user_id, ensuring RevenueCat purchases, OneSignal notifications, and other services follow the user across devices.
Flow Diagram: Complete Picture
Summary
| Concept | What to remember |
|---|---|
oauth:// | Opens secure browser (ASWebAuth / CustomTabs) |
{scheme}://oauth/ | Closes browser, the oauth/ prefix is required |
/native-callback | Runs in browser, exchanges code, redirects to deeplink |
/auth (or similar) | Runs in WebView, receives tokens, completes login |
| State parameter | Include deeplink scheme for proper browser closing |
| Token handoff | Via URL params in the deeplink redirect |
| Identity linking | Connect OAuth identity to app_user_id via login endpoint |