# KMPAuth: one authentication API across Android, iOS, desktop and web

> KMPAuth is a Kotlin Multiplatform authentication library for Compose Multiplatform apps that offers Google, Apple, Facebook, GitHub, Microsoft, email, magic link, phone and anonymous sign-in from commonMain on every target, backed by Firebase, Supabase or your own server. The platform matrix in the README is where the real detail is.

**mirzemehdi/KMPAuth** — Kotlin Multiplatform Authentication Library targetting android, iOS, desktop and web

- Repository: https://github.com/mirzemehdi/KMPAuth
- Website: https://mirzemehdi.com/KMPAuth/
- Stars: 560 · Forks: 54
- Language: Kotlin
- License: Apache-2.0
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/mirzemehdi-kmpauth

## The problem is that auth is per-platform

KMPAuth is a Kotlin Multiplatform Authentication Library targeting android, iOS, desktop and web, and the reason it exists is visible in the list of sign-in methods: Google, Apple, Facebook, GitHub, Microsoft, email and password, magic links, phone number, or anonymously.

Each of those has a native implementation on some platforms and not others. Apple sign-in has a native flow on iOS and a browser redirect everywhere else. Facebook has a native SDK on Android and iOS and a browser flow on desktop and web. Phone number authentication needs the mobile SDKs unless the backend is Supabase. A team building for several platforms at once ends up writing the same sign-in logic several times, with a different shape on each target, which is exactly the duplication a multiplatform library is supposed to remove.

The library's answer is that every API is callable from commonMain on every target, and that a feature unavailable on the current platform reports a failed Result with the reason instead of not compiling or silently doing nothing. That last property is the design decision that matters most. A multiplatform library that simply omits an API on a target forces expect/actual branches in your code; one that returns a failed Result keeps one signature and lets you handle the failure at runtime.

The primary language is Kotlin, the licence is Apache-2.0, the default branch is main, and the last push was on 2026-09-04 with releases 3.0.6, 3.0.5 and 3.0.4 in August and September 2026. The homepage is https://mirzemehdi.com/KMPAuth/ and the README badge shows Kotlin 2.4.0.

## Two backends, and the matrix that decides your setup

The README frames the decision as two questions: which backend runs on your platforms, and which methods that backend serves. That is a more useful framing than a list of features, because the platform support table is where the real detail is.

The backends are Firebase and Supabase, or your own server, where your own server means no backend is needed because the state hands you the provider's token to verify yourself. Firebase and Supabase are both listed as working across Android, iOS, Desktop, Web JS and Web wasm, with one qualification on the Firebase side.

That qualification is footnote 2, and it is the kind of detail that decides a project. Firebase on wasm runs on the REST engine, with no Firebase SDK there. The listed capabilities are email, anonymous, id-token exchange, email link, password reset and reauthentication. What is not there is browser web flows and phone. So a Firebase-backed app targeting WebAssembly has a smaller method set than the same app targeting Web JS, even though both are web.

The method table then goes through each sign-in method against each target. Google works everywhere with every backend. Email with password, reset and magic link works everywhere with Firebase or Supabase. Anonymous works everywhere. Phone number works everywhere but with footnote 3, which says it is beyond Android and iOS only with Supabase using SMS OTP, while Firebase phone auth needs the mobile SDKs.

So the honest summary is that the library is broad but not uniform, and the footnotes are where the exceptions live. Anyone planning a project should read that table against their own backend and target set rather than assuming the headline list applies everywhere.

## Installing: provider modules and one backend module

The installation is a Gradle dependency block in commonMain, and the split of modules is the key to understanding it. The identity provider modules give you native SDK sign-in with no backend required, and the backend modules are separate, and you pick one or both.

```kotlin
commonMain.dependencies {
    // Identity providers - native SDK sign-in, no backend required:
    implementation("io.github.mirzemehdi:kmpauth-google:<version>")   // Google sign-in
    implementation("io.github.mirzemehdi:kmpauth-apple:<version>")    // if needed: native Sign in with Apple (iOS)
    implementation("io.github.mirzemehdi:kmpauth-facebook:<version>") // if needed: Facebook login (Android/iOS)

    implementation("io.github.mirzemehdi:kmpauth-uihelper:<version>") // if needed: branded sign-in buttons

    // Session backend - pick one (or both):
    implementation("io.github.mirzemehdi:kmpauth-firebase:<version>") // Firebase backend
    implementation("io.github.mirzemehdi:kmpauth-supabase:<version>") // if needed: Supabase backend
}
```

Two details are worth noting. The comment on the uihelper module says branded sign-in buttons, which is the common pattern of a Compose Multiplatform app wanting its own button artwork rather than the provider's stock UI, and keeping that in a separate module means a project that does not want it does not pull it in. And the group and artifact naming are consistent, io.github.mirzemehdi with a kmpauth- prefix and a version placeholder.

For iOS, the native SDKs are added via Swift Package Manager, with the detail in the getting started document, which is the standard arrangement for a Kotlin Multiplatform library that needs to link against Apple frameworks.

The repository layout shows how the modules are organised: kmpauth-core/ and kmpauth-uihelper/ at the top level, providers/ for the identity provider modules, backends/ for the session backends, plus build-logic/, sampleApp/, docs/, a deprecated/ directory and a kotlin-js-store/. The deprecated/ directory suggests earlier module names were kept around rather than removed, and MIGRATION.md at the root confirms that the module layout has changed across versions.

## Three setup shapes, from bare token to managed session

The Pick your setup section offers three configurations, and they differ in how much the library does for you.

The first is no backend, where you verify the token yourself. Only the provider modules are used, and the rememberXxxSignInState states hand you the provider's credential and stop there, so you send it to your own server.

```kotlin
KMPAuth.initialize {
    google(serverId = WebClientId)
}

val googleSignIn = rememberGoogleSignInState(onResult = { result ->
    result.onSuccess { googleUser ->
        api.login(googleUser.idToken) // verify server-side
    }.onFailure { error -> /* cancelled, misconfigured, ... */ }
})
GoogleSignInButton { googleSignIn.launch() }
```

The second is Firebase, where adding kmpauth-firebase makes the backend register itself and on Android and iOS there is zero configuration because the SDK reads google-services.json or GoogleService-Info.plist. The rememberXxxAuthState states then exchange the credential for a Firebase session, and the account operations live on KMPAuth itself.

```kotlin
KMPAuth.initialize {
    google(serverId = WebClientId)
    // Desktop/Web only - Android/iOS use the bundled config files:
    firebase(apiKey = "...", projectId = "...", applicationId = "...")
}

val googleSignIn = rememberGoogleAuthState(onResult = onResult)
GoogleSignInButton { googleSignIn.launch() }

val appleSignIn = rememberAppleAuthState(onResult = onResult)       // native on iOS, web flow elsewhere
val facebookSignIn = rememberFacebookAuthState(onResult = onResult) // kmpauth-facebook, Android/iOS
val githubSignIn = rememberGithubAuthState(onResult = onResult)     // browser OAuth web flow
val microsoftSignIn = rememberMicrosoftAuthState(onResult = onResult)
val emailSignIn = rememberEmailAuthState(email, password, onResult = onResult)
val phoneSignIn = rememberPhoneAuthState(phoneNumber, onResult = onResult)
val guestSignIn = rememberAnonymousAuthState(onResult = onResult)

KMPAuth.currentUser()
KMPAuth.signOut()
KMPAuth.sendPasswordResetEmail(email)
KMPAuth.reauthenticate(AuthCredential.EmailPassword(email, password))
```

The comments on those lines are the useful part, because each one tells you where the flow differs: Apple is native on iOS and a web flow elsewhere, Facebook works on Android and iOS, GitHub is always a browser OAuth web flow.

The third is Supabase, documented in its own guide, and the difference from Firebase is that Supabase accepts Facebook Limited Login tokens, which are OIDC tokens, while Meta's own SDK exists only on Android and iOS.

Across all three the shape is the same: a rememberXxxAuthState composable that produces a Result, and either a provider module, a backend module, or both.

## The footnotes, where the platform differences actually live

The four footnotes under the support table are the most useful part of the documentation, and each one describes a case where the obvious implementation would have been wrong.

Footnote 1 covers Facebook. Supabase accepts Facebook Limited Login tokens only, and those are OIDC tokens. Meta's SDK exists only on Android and iOS, and on other platforms you use the browser OAuth row, either with rememberOAuthState("facebook.com") on Firebase or OAuthWebFlow("facebook.com") on Supabase. So the same Facebook login is two different integrations depending on the target, which is a good illustration of why the per-platform notes exist at all.

Footnote 2 is the Firebase on wasm REST engine case described earlier.

Footnote 3 covers phone number, which is beyond Android and iOS only with Supabase using SMS OTP, since Firebase phone auth needs the mobile SDKs.

Footnote 4 is the Supabase-only restriction on GitHub, Microsoft, Facebook-web and any OAuth. The call is KMPAuth.signIn(AuthCredential.OAuthWebFlow("github.com")), desktop works out of the box, Android and iOS need Supabase's deep-link setup, and on web the flow is a full-page redirect with the session restored after reload.

That last one is a real design consequence rather than a limitation to work around. A full-page redirect on web means the in-app state is torn down and rebuilt, and the session is recovered afterwards, so an app that depends on unsaved in-memory state at the moment of sign-in has to account for that.

The Apple native token row is also restricted: no backend means it works on iOS only, and there is no Android, Desktop or Web entry at all, because native Apple sign-in has no equivalent outside the platform.

## Where this library is the wrong tool

There are three limits, and they come from different directions.

The first is platform coverage that is broad but not uniform. A method that works on five targets can still be missing on the sixth, and the footnotes show that even within one method, the implementation differs by target. Teams that assume a single uniform API will find the exceptions in code, and the failures are reported as a failed Result rather than a compile error, so they surface at runtime rather than at build time. That is the right behaviour for a library, but it means you need to handle the failure path rather than assume it away.

The second is the choice between a managed session and your own server. The no-backend mode hands you a token and stops. Everything about session management, token refresh and revocation is then your problem, and KMPAuth is not helping. The Firebase and Supabase modes give you a managed session, and you give up the freedom to own that layer and to avoid a vendor dependency in your auth path.

The third is the maintenance surface. The library wraps native SDKs for Google, Apple, Facebook and Supabase as well as Firebase, and each of those SDKs changes on its own schedule. A wrapper has to track them, and a multiplatform wrapper tracks several at once across five targets. The version numbers in the repository are recent, with three releases in August and September 2026, and a CHANGELOG.md and MIGRATION.md at the root, which is what you would expect from a library that has had to change its module layout before.

The honest alternative is to use each platform's own SDK and accept the duplication, which is the right call for a single-platform app. For a team that already has a backend and an established session scheme, the no-backend mode is a small addition on top of that, and for a team without one, the Firebase or Supabase path saves more than it costs.

## Conclusion

Adopt KMPAuth if you ship a Compose Multiplatform app and want one authentication API rather than a separate implementation per platform, since the commonMain surface is the point of the library. Do not adopt it if your app targets a single platform, where a platform SDK is simpler. Before you start, read the supported-where table for your backend and target combination, since the footnotes show real gaps, and note the last push was on 2026-09-04 with release 3.0.6 the same day.

## FAQ

### What is KMPAuth and which platforms does it target?

It is a Kotlin Multiplatform authentication library for Compose Multiplatform apps, covering Android, iOS, Desktop on the JVM and Web on both JS and wasm. Every API is callable from commonMain on every target, and a feature unavailable on the current platform reports a failed Result with the reason.

### Which sign-in methods does KMPAuth support and what backends does it need?

Google, Apple, Facebook, GitHub, Microsoft, email with password, reset and magic link, phone number and anonymous sign-in, served by Firebase, Supabase or your own server where the state simply hands you the provider's token to verify yourself.

### Which Gradle modules do I add to use KMPAuth?

The identity provider modules such as kmpauth-google, kmpauth-apple, kmpauth-facebook and kmpauth-uihelper, plus one or both backend modules, kmpauth-firebase and kmpauth-supabase, all under the io.github.mirzemehdi group. On iOS the native SDKs are added through Swift Package Manager.

### What are the limitations of KMPAuth on WebAssembly and for phone sign-in?

Firebase on wasm runs on the REST engine with no Firebase SDK, so email, anonymous, id-token exchange, email link, password reset and reauthentication work but browser web flows and phone do not. Phone number sign-in is beyond Android and iOS only with Supabase using SMS OTP, because Firebase phone auth needs the mobile SDKs.

### How does KMPAuth handle OAuth providers such as GitHub on web?

The OAuth web flow is Supabase only, through KMPAuth.signIn(AuthCredential.OAuthWebFlow("github.com")). Desktop works out of the box, Android and iOS need Supabase's deep-link setup, and on web the flow is a full-page redirect with the session restored after reload.

## Sources

- [License: Apache-2.0](https://github.com/mirzemehdi/KMPAuth/blob/main/LICENSE)
- [mirzemehdi/KMPAuth on GitHub](https://github.com/mirzemehdi/KMPAuth)
- [Project website](https://mirzemehdi.com/KMPAuth/)
- [README](https://github.com/mirzemehdi/KMPAuth/blob/main/README.md)
- [Releases](https://github.com/mirzemehdi/KMPAuth/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/mirzemehdi-kmpauth
