Picture the bug report that lands twice. A token refresh fails silently, users get logged out mid-session, and you fix it. On Android. In Kotlin. Then you open the iOS project and fix the same logic again — different language, different SDK, same sentence of intent written a second way. Two teams, two pull requests, one idea.
That duplication is the quiet tax on every mobile app that ships for both phones. Your login screen does the same thing on an iPhone and a Pixel: send the user to Auth0, get them back signed in, stash the tokens somewhere a thief can’t reach. But historically you built it twice, because iOS and Android don’t speak the same language.
Auth0 just released an SDK that lets you write that logic once, in Kotlin, and run it on both. To understand why that’s more interesting than it sounds, you need to understand the trick underneath it.
The universal adapter, explained
Kotlin Multiplatform — KMP from here on — is a way of compiling the same Kotlin source to different targets. One target is the JVM, which Android runs on. Another is native machine code for iOS, via a compiler called Kotlin/Native. Same source, two outputs.
Think of it like a travel power adapter. The plug on your laptop charger never changes — that’s your shared code, the logic that’s identical everywhere. The adapter has swappable prongs for the UK, the EU, the US. Those prongs are the small bits that have to be different per country. You carry one charger and three prongs, not three chargers.
KMP formalises this with a feature called expect/actual. In the shared layer you write expect — “I expect something that can do X here, I don’t care how.” Then each platform supplies the actual — the real implementation using that platform’s native machinery. Your shared code calls a function; the right prong snaps in at compile time.
This matters enormously for authentication, because the two hardest parts of mobile auth are exactly the parts that must be platform-specific.
Where auth refuses to be portable
Two jobs. First, opening a browser so the user can log in — the OAuth flow Auth0 calls Universal Login, where the actual password entry or passkey prompt happens in a secure system browser rather than inside your app. On iOS that’s ASWebAuthenticationSession. On Android it’s a Custom Tab. Totally different APIs, same purpose.
Second, storing the tokens you get back. After login you hold an access token and a refresh token — the refresh token especially is a long-lived key to the user’s account, and you do not want it sitting in plain storage. iOS has the Keychain. Android has the Keystore and encrypted storage. Again: different mechanisms, identical intent.
This is the elegant bit. The KMP SDK puts login, logout, and token storage behind one Kotlin API, and uses expect/actual to wire the iOS calls to Keychain and ASWebAuthenticationSession, and the Android calls to the Keystore and Custom Tabs — without you touching either. You write against the shared surface. The prongs are already in the box.
What logging in actually looks like
You configure a client once, in shared code, with your tenant domain and client ID — the same two values you’d paste into either native SDK:
Then the login flow is a suspending function — Kotlin coroutines, so it reads top to bottom instead of drowning in callbacks:
Logout mirrors it, and clearing stored credentials is one call:
That entire block lives in your shared module. It compiles into the iOS app and the Android app. The bug you fixed once stays fixed in both. Treat the exact names as illustrative — check the SDK’s current API reference, since early releases move.
This is not a replacement, and Auth0 isn’t pretending it is
Let me be blunt about where the shared dream stops, because a vendor blog won’t lead with it.
Auth0 already ships two mature, battle-tested native SDKs: Auth0.swift for iOS and Auth0.Android in Kotlin. These have years of production mileage, deep platform integration, and feature coverage the new KMP SDK does not yet match. The multiplatform SDK is additive. It’s a third door, not a demolition of the first two.
The honest trade-offs:
- Feature lag. A new SDK built to serve two platforms through one API will trail the native ones on platform-specific niceties. If you need something that only exists on iOS or only on Android, you may still drop down to the native SDK — or write your own
actualimplementation in the platform source set. That’s the escape hatch KMP gives you, but it’s extra code you own. - Maturity. New SDK, newer edge cases. Native Auth0.swift and Auth0.Android have had the obscure bugs filed and fixed by other people already. Check the release status and open issues before you bet a shipping app on it.
- Build complexity. KMP isn’t free to adopt. If you’re not already using it, standing up the shared module, the Gradle targets, and the iOS framework packaging is real work. Auth is a poor reason to adopt KMP on its own.
Who should actually reach for this
The answer follows from that last point. If your team already runs Kotlin Multiplatform — shared networking, shared models, shared business logic feeding a SwiftUI frontend and a Compose frontend — then authentication was the awkward exception. You’d carved out auth as the one thing you still wrote twice. This SDK lets auth follow the same pattern as everything else. For those teams it’s close to a no-brainer.
If you ship native-only apps, one team per platform, no shared Kotlin anywhere — stay on Auth0.swift and Auth0.Android. They’re more complete, and you gain nothing by introducing a multiplatform toolchain just to consolidate a few hundred lines of login code.
And if you’re somewhere in between — considering KMP, curious whether auth would travel with it — this release removes one of the better excuses not to. The hard, platform-bound parts of mobile auth, the browser session and the secure token vault, are exactly what the SDK now abstracts for you. That used to be the reason people said auth couldn’t be shared.
The login screen you wrote twice isn’t gone. But for the right team, it just became something you write once and forget — which is the entire point of writing anything once.
