This document describes the complete headless/API-only authentication implementation for the Axis Tauri app. The system now supports both web-based authentication (using Stack/Neon Auth) and headless authentication for Tauri production builds.
The app automatically detects the environment and chooses the appropriate authentication provider:
- Web/Development: Uses Stack Auth React components directly
- Tauri Production: Uses custom headless authentication with browser-based OAuth
Detection logic in src/contexts/AuthContext.tsx:
export function shouldUseHeadlessAuth(): boolean {
return isTauriEnvironment() && isProductionBuild()
}-
Auth Routes (
src/routes/auth.ts)POST /auth/initiate- Creates auth session and returns OAuth URLGET /auth/status/:sessionId- Polling endpoint for auth statusGET /auth/callback- OAuth callback (Stack/Neon)POST /auth/exchange- Manual token exchangePOST /auth/refresh-token- Token refresh endpoint
-
Auth Session Manager (
src/services/authSession.ts)- Manages temporary auth sessions with 5-minute TTL
- Tracks session status and user data
- Automatic cleanup of expired sessions
-
Auth Context (
src/contexts/AuthContext.tsx)- Defines standard auth interface matching Stack Auth API
- Type guards for environment detection
-
Tauri Auth Provider (
src/providers/TauriAuthProvider.tsx)- Custom auth provider for Tauri builds
- Token persistence using SecureStorage
- Automatic token refresh every 5 minutes
- Session validation on mount
-
Unified Auth Hooks (
src/hooks/useAppAuth.ts)useAppAuth()- Unified auth hookuseAppUser()- Unified user hook- Automatically selects correct provider based on environment
-
Auth Polling (
src/hooks/useAuthPolling.ts)- Polls backend for auth completion
- Visual progress indicators
- Configurable timeout and retry logic
-
Browser Auth (
src/lib/browserAuth.ts)- Initiates OAuth sessions
- Opens system browser for authentication
- Token exchange functionality
-
Secure Storage (
src/lib/secureStorage.ts)- Uses Tauri keyring for desktop
- Falls back to localStorage for web
- Handles both access and refresh tokens
sequenceDiagram
participant App as Tauri App
participant Backend as Backend Server
participant Browser as System Browser
participant Clerk as Clerk Auth
App->>Backend: POST /auth/initiate
Backend->>App: Return sessionId & authUrl
App->>Browser: Open authUrl
Browser->>Clerk: User authenticates
Clerk->>Backend: Redirect to /auth/callback
Backend->>Backend: Validate & store token
Backend->>Browser: Show success page
loop Polling
App->>Backend: GET /auth/status/:sessionId
Backend->>App: Return auth status
end
App->>App: Store tokens securely
App->>App: Navigate to dashboard
- Desktop: Uses OS keychain via Tauri commands
- Web: Uses localStorage as fallback
- Tokens refresh automatically on 401 responses
- Background refresh every 5 minutes
- Seamless retry with exponential backoff
The aiHttpApi.ts client handles token refresh:
if (response.status === 401 && retryCount === 0) {
// Try to refresh token
const refreshResponse = await fetch(`${backendUrl}/auth/refresh-token`, {
method: 'POST',
body: JSON.stringify({ refreshToken })
})
// Retry original request with new token
}- Browser-based authentication for Tauri
- Visual polling indicators with progress bar
- Cancel and retry functionality
- Manual token entry as fallback
- Smooth transitions and animations
- Automatic session restoration on app restart
- Token validation on mount
- Graceful degradation for expired sessions
Replace Clerk imports with unified hooks:
// Before
import { useAuth, useUser } from '@clerk/clerk-react'
// After
import { useAppAuth, useAppUser } from '@/hooks/useAppAuth'The API remains the same:
const { isSignedIn, getToken, signOut } = useAppAuth()
const { user } = useAppUser()Backend requires:
CLERK_SECRET_KEY=sk_test_...
CLERK_DOMAIN=your-instance.accounts.dev
BACKEND_URL=https://api.yourapp.com
ALLOWED_ORIGINS=tauri://localhost,https://yourapp.com- Token Storage: Uses OS keychain for maximum security
- Session Management: Short-lived sessions (5 minutes)
- CORS Configuration: Strict origin validation
- Token Validation: Server-side verification of all tokens
- Automatic Cleanup: Expired sessions removed regularly
- Uses Clerk components directly
- Standard web authentication flow
- Hot reload works normally
# Build for production
npm run tauri:build
# Test authentication flow
1. Click "Sign In with Browser"
2. Complete authentication in browser
3. App detects completion automatically
4. Tokens stored securely
5. Session persists across restarts-
Authentication not detected
- Check backend is accessible
- Verify CLERK_DOMAIN is correct
- Check browser console for errors
-
Token refresh failures
- Verify refresh endpoint is working
- Check token expiration times
- Review backend logs
-
Session persistence issues
- Verify Tauri keyring permissions
- Check SecureStorage implementation
- Review console logs for errors
- OAuth PKCE - Add code challenge/verifier
- SSO Support - Enterprise authentication
- Biometric Auth - TouchID/FaceID support
- Multi-factor Auth - Enhanced security
The headless authentication system provides a robust, secure, and user-friendly authentication experience for Tauri desktop applications while maintaining compatibility with web deployments. The implementation follows best practices for native app authentication and provides excellent user experience with visual feedback and error recovery.