@eurora-labs/tauri-plugin-appauth
v0.2.0
Published
Tauri 2 mobile plugin that bridges OAuth 2.0 / OIDC flows to AppAuth-iOS and AppAuth-Android.
Readme
tauri-plugin-appauth
A Tauri 2 mobile plugin that bridges OAuth 2.0 / OIDC flows to the OpenID Foundation's AppAuth-iOS and AppAuth-Android reference clients. Discovery, dynamic client registration, PKCE-secured authorization, token refresh, and RP-initiated end-session are exposed as a single typed TypeScript + Rust API.
Status: 0.2.0 rewrite in progress. The crate is being rebuilt on top of AppAuth in successive phases. Until the rewrite ships, the only working command is the legacy
authenticate(browser-leg only) flow.
Platform support
| Platform | Status |
|---|---|
| iOS 15+ | Supported via AppAuth-iOS |
| Android 24+ | Supported via AppAuth-Android |
| Desktop | Returns UNSUPPORTED_PLATFORM; use tauri-plugin-oauth instead. |
Install
Cargo:
[dependencies]
tauri-plugin-appauth = "0.2"npm / bun:
bun add @eurora-labs/tauri-plugin-appauth
# or
npm install @eurora-labs/tauri-plugin-appauthRegister the plugin in your Tauri app's mobile entry point:
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_appauth::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}Configure
Android
Declare the OAuth redirect scheme as a manifest placeholder in your app's
build.gradle.kts. AppAuth's redirect-receiver activity is merged in
automatically; you do not need to register one yourself.
android {
defaultConfig {
manifestPlaceholders["appAuthRedirectScheme"] = "com.example.app"
}
}iOS
Add your custom URL scheme to Info.plist if you use one, and ensure the
Associated Domains entitlement is set if you use Universal Links for the
redirect.
Building from source
Plugin host apps consume the published crate; they do not need any of the steps below. These notes are for contributors hacking on this repository.
The Android library expects a vendored copy of the Tauri runtime API at
android/.tauri/tauri-api/, which is not committed to this repository.
It is regenerated by the plugin's build.rs whenever cargo build runs,
because tauri_plugin::Builder::android_path("android") snapshots the
Tauri version pinned in Cargo.toml into that directory.
Bootstrap an Android development checkout:
cargo build # populates android/.tauri/tauri-api/
cd android
echo "sdk.dir=$ANDROID_HOME" > local.properties # or let Android Studio create it
gradle assembleDebug # optional: build the AAR in isolationandroid/local.properties, android/.gradle/, android/.kotlin/, and
android/build/ are likewise gitignored — they hold per-machine SDK paths
and Gradle caches.
Permissions
Add the plugin's default permission to your capabilities:
{
"permissions": ["appauth:default"]
}The default permission set will, after the rewrite, expose discover,
authorize, authorizeBrowserOnly, refresh, and endSession. The more
sensitive register (RFC 7591 Dynamic Client Registration) ships with the
plugin but is not included in the default set — opt in explicitly with
appauth:allow-register when you need it.
Quickstart (target API)
import { authorize, AppAuthError } from '@eurora-labs/tauri-plugin-appauth';
try {
const auth = await authorize({
config: { kind: 'discovery', issuer: 'https://accounts.google.com' },
clientId: '...apps.googleusercontent.com',
redirectUri: 'com.example.app:/oauth/callback',
scopes: ['openid', 'email', 'profile'],
});
// auth.accessToken, auth.idToken, auth.refreshToken
} catch (e) {
if (e instanceof AppAuthError && e.code === 'USER_CANCELED') return;
throw e;
}For backend-mediated flows that only need the browser leg, authorizeBrowserOnly
returns the redirect URL without performing the code-for-token exchange.
Error reference
Errors are normalized to a stable enum derived from AppAuth's OIDErrorCode
(iOS) and AuthorizationException categories (Android):
| Code | Meaning |
|---|---|
| USER_CANCELED | The user dismissed the in-app browser. |
| AUTHORIZATION_FAILED | The authorization endpoint returned an error. |
| TOKEN_EXCHANGE_FAILED | Code-for-token exchange failed. |
| NETWORK_ERROR | Underlying transport failure. |
| INVALID_REGISTRATION_RESPONSE | DCR response was malformed. |
| ID_TOKEN_VALIDATION_FAILED | OIDC ID token signature/claims rejected. |
| BROWSER_NOT_AVAILABLE | No Custom Tabs / ASWebAuthenticationSession available. |
| INVALID_REQUEST | The plugin received malformed inputs. |
| SERVER_ERROR | Token endpoint returned a 5xx. |
| UNSUPPORTED_PLATFORM | Called on desktop. |
| PLUGIN_INVOKE_FAILED | IPC bridge failed before the native side ran. |
License
Apache-2.0. See LICENSE.
