Introduction to the OAuth Plugin
Understand the Tauri OAuth plugin, how it solves authentication challenges in desktop apps, and the basic authentication flow it enables
Modern desktop applications often need to let users sign in with Google, GitHub, or other identity providers. A website can simply register a redirect URL like https://myapp.com/callback, but a desktop app has no natural web address to receive that redirect. The OAuth plugin for Tauri v2 solves this by running a tiny local HTTP server that captures the redirect and hands the result back to your app.
What Is the OAuth Plugin?
The OAuth plugin (tauri-plugin-oauth) is a community-maintained Tauri plugin that spawns a temporary localhost server to receive OAuth 2.0 authorization code redirects. It works with any OAuth provider that can redirect to http://localhost — Google, GitHub, Auth0, and many more.
When you trigger a login, the plugin starts a server on a random available port, opens the provider's authorization page in the system browser, listens for the callback, and passes the full redirect URL (containing the authorization code) to your Rust or frontend code. You then exchange that code for tokens, typically on a backend server.
Not a built-in Tauri plugin:
Tauri v2 does not ship a built-in OAuth plugin. The plugin described here is the most widely used community solution for desktop OAuth flows. For mobile, a different approach using platform-native auth sessions is required.
Why You Need an OAuth Plugin in Tauri
OAuth 2.0 was designed with web apps in mind. The standard flow expects the authorization server to redirect the user back to a URL that the client controls. On a website that URL lives at a registered domain. In a desktop app, there is no persistent public endpoint to serve as a redirect destination.
Three typical workarounds exist:
- Embed a WebView and intercept navigation — fragile, insecure (credentials can leak into the WebView), and many providers block login in embedded browsers.
- Use a custom protocol / deep link — works on some platforms, but many OAuth providers (including Google) do not allow custom URI schemes as redirect URIs.
- Run a local HTTP server — binds to
127.0.0.1, registershttp://localhostas the redirect URI, and captures the callback. This is the approach the plugin uses.
The plugin automates option 3. It handles the server lifecycle, port binding, and the low-level HTTP dance, so you can focus on the authentication logic.
How the Plugin Works
The core idea is straightforward. The plugin:
- Starts an HTTP server bound to
127.0.0.1on a free port (or a specific port you provide). - Gives you that port so you can build an authorization URL like
http://localhost:8001/callbackand open it in the default browser. - When the provider redirects back to that localhost URL, the server captures the full query string — including the
codeandstateparameters. - Invokes a callback that you register, either a Rust closure or an event emitted to the frontend.
- Optionally returns a friendly HTML page to the browser so the user sees a success message instead of a connection error.
You remain responsible for verifying the state parameter (CSRF protection), implementing PKCE, and exchanging the authorization code for tokens. The plugin is a transport layer — it does not perform token exchange or token storage.
Supported Platforms
The tauri-plugin-oauth plugin targets desktop platforms only — macOS, Windows, and Linux. It works anywhere Tauri v2 runs, because the core mechanism (binding a TCP listener on localhost) is universally available.
For mobile (iOS and Android), you need a different approach. On those platforms, the system provides native APIs for in-app browser authentication (ASWebAuthenticationSession on Apple, Chrome Custom Tabs on Android). The tauri-plugin-auth-session plugin wraps these APIs.
Know your target:
If you plan to release on mobile, you will need a separate authentication path. The OAuth plugin described in this chapter handles desktop authentication only.
Common OAuth Providers
Any provider that supports the authorization code flow with PKCE and allows http://localhost as a redirect URI works with the plugin. Frequently used providers include:
- Google — requires creating a "Web application" OAuth client ID with
http://localhostin the authorized redirect URIs. - GitHub — supports localhost redirects; you register an OAuth app with a callback URL like
http://localhost:8000/callback. - Auth0 — allows localhost redirects for native applications.
- Keycloak and other self-hosted identity providers.
- Microsoft Entra ID, Okta, GitLab, and many others.
Key Features
| Feature | Description |
|---|---|
| Automatic port binding | Binds to a random available port, or a port you specify, avoiding conflicts. |
| Customizable response | Returns a configurable HTML page or a 302 redirect to another URL after capturing the code. |
| Multiple ports fallback | Accepts a list of ports to try, which is helpful in restricted environments. |
| Event-based API | Emits a Tauri event with the full redirect URL, making it easy to handle from your frontend. |
| Rust closure support | Alternatively, register a Rust closure to process the URL directly in the backend. |
Basic Authentication Flow
The OAuth flow with the plugin follows a precise sequence. Each step depends on the previous one.
Start the local OAuth server
From your Rust command, call start() (or start_with_config()) to begin listening on localhost. The function returns the port number.
#[tauri::command]
async fn start_oauth(window: tauri::Window) -> Result<u16, String> {
tauri_plugin_oauth::start(move |url| {
let _ = window.emit("oauth-callback", url);
})
.map_err(|e| e.to_string())
}
Build the authorization URL and open the browser
With the port, construct the provider's /authorize endpoint URL. Set redirect_uri to http://localhost:<port>. Include PKCE parameters (code_challenge, code_challenge_method) and a random state. Then open the URL in the system browser.
User authenticates and grants consent
The user logs into the provider in their default browser and approves the requested scopes. Because this is the system browser, all existing sessions and security protections apply.
Provider redirects to localhost
The provider sends a GET request to http://localhost:<port>/?code=...&state=.... The plugin's internal HTTP server captures this request.
Plugin delivers the callback URL
The plugin calls your registered handler — either a Rust closure or a Tauri event like oauth-callback. You now have the full URL with the authorization code.
Exchange the code for tokens
Send the authorization code, together with the code verifier, client ID, and (on a secure backend) client secret, to the provider's token endpoint. Receive access and refresh tokens in response. This step should happen server-side to avoid exposing secrets.
You're on the right track:
If your handler receives a URL containing code and state parameters after the user authorizes, the plugin has done its job correctly. The rest is standard OAuth token exchange.
Do not skip PKCE:
The authorization code flow without PKCE is vulnerable to authorization code interception. Always generate a new code_verifier and code_challenge for each login attempt, and validate the state parameter to prevent CSRF attacks. The plugin provides the transport; you must implement these protections.
Quick Setup
To add the plugin to your project, install both the Rust crate and the JavaScript API package.
npm install @fabianlars/tauri-plugin-oauth@2
Then add the crate to src-tauri/Cargo.toml:
[dependencies]
tauri-plugin-oauth = "2"
Register the plugin in your Tauri builder:
use tauri_plugin_oauth;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_oauth::init())
.invoke_handler(tauri::generate_handler![start_oauth]) // your command
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
Finally, add the required permission to your capabilities file:
{
"permissions": [
"tauri-plugin-oauth:default"
]
}
Security Considerations at a Glance
The plugin handles the redirect capture, but security is still your responsibility. The most critical rules:
- Never embed a client secret in your frontend code. Desktop and mobile apps cannot hide secrets. Perform the token exchange on a backend server you control, or use a public-client flow that does not require a secret.
- Always use PKCE — generate a random code verifier, hash it, and send the challenge with the authorization request. The plugin does not enforce PKCE; it's up to your application.
- Validate the
stateparameter in the redirect to prevent CSRF attacks. - Use the authorization code flow, not the implicit flow, and always exchange the code server-side.
These practices are not plugin-specific — they apply to any OAuth implementation. The plugin removes the platform-specific plumbing so you can focus on getting the security right.
Summary
The OAuth plugin fills the gap between the web-centric OAuth specification and the reality of desktop application development. By running a local server, it gives your app a stable, secure redirect endpoint without requiring a public domain or a custom URI scheme. The authentication flow becomes straightforward: start a server, open a browser, capture the callback, exchange the code.