gau is a flexible, self-hostable OAuth2.1 library similar to Auth.js, built with first-class Tauri support.
- Everything-agnostic: Framework, runtime, and database agnostic
- Web Standards: Uses Web Crypto and Fetch APIs exclusively
- Self-hostable: No docker and stuff, run anywhere
- TypeScript-first: Fully typed with strong type inference
packages/gau/src/
├── core/ # Framework-agnostic auth logic
├── adapters/ # Database adapters (Drizzle: SQLite, PostgreSQL, MySQL)
├── oauth/ # OAuth providers (GitHub, Google, Discord, Facebook, Microsoft)
├── jwt/ # JWT signing/verification (ES256, HS256)
├── client/ # Frontend client helpers (Svelte, SolidJS, Vanilla)
├── sveltekit/ # SvelteKit integration
├── solidstart/ # SolidStart integration
└── runtimes/ # Runtime-specific code (Bun, Tauri)Creates the auth instance with all configuration:
const auth = createAuth({
adapter, // Database adapter (required)
providers, // OAuth providers array (required)
basePath, // API route prefix (default: '/api/auth')
jwt: { secret }, // JWT config with secret
cookies: {}, // Cookie configuration
roles: {}, // Role-based access control config
profiles: {}, // Provider-specific profile overrides
// Hooks:
onOAuthExchange, // Intercept OAuth callback
mapExternalProfile, // Transform provider user data
onBeforeLinkAccount,
onAfterLinkAccount
})Returns a (Request) => Promise<Response> function handling these routes:
GET /:provider- Start OAuth flowGET /callback/:provider- OAuth callbackGET /link/:provider- Link additional accountGET /session- Get current sessionPOST /signout- Sign outPOST /token- Exchange tokenPOST /unlink/:provider- Unlink account
- Cookie-based: Default for web apps, uses
gau_sessioncookie - Token-based: For mobile/Tauri apps, uses Bearer token
- Sessions are JWTs containing
sub(user ID) and custom claims
Issue a session for any user without OAuth flow. Returns both token and Set-Cookie header:
const { token, cookie, cookieName, maxAge } = await auth.issueSession(userId, {
data: { isGuest: true }, // Custom claims
ttl: 3600 // Override default TTL
})
// Web: Set cookie in response
response.headers.set('Set-Cookie', cookie)
// Mobile/Tauri: Use Bearer token
fetch(url, { headers: { Authorization: `Bearer ${token}` } })Use cases: guest login, invite redemption, admin impersonation, device claiming.
Refresh an existing session, issuing a new token with extended TTL. Preserves custom claims:
const refreshed = await auth.refreshSession(token, {
ttl: 3600, // Override TTL
threshold: 0.5 // Only refresh if past 50% of TTL
})
if (refreshed)
response.headers.set('Set-Cookie', refreshed.cookie)Returns null if token is invalid/expired/below threshold or user no longer exists.
Users can link multiple OAuth providers to one account. Controlled by:
autoLink:'verifiedEmail'|'always'|'never'allowDifferentEmails: Allow linking accounts with different emailsupdateUserInfoOnLink: Update user profile when linking
interface User {
id: string
name?: string | null
email?: string | null
emailVerified?: boolean | null
image?: string | null
role?: string | null
}
interface Session {
id: string
sub: string // User ID
[key: string]: unknown
}
interface Adapter {
getUser
getUserByEmail
getUserByAccount
getAccounts
getUserAndAccounts
createUser
updateUser
deleteUser
linkAccount
unlinkAccount
updateAccount
}// src/routes/api/auth/[...gau]/+server.ts
import { SvelteKitAuth } from '@rttnd/gau/sveltekit'
export const { GET, POST, handle } = SvelteKitAuth(auth)
// Client: use createSvelteAuth() or useAuth()import { SolidStartAuth } from '@rttnd/gau/solidstart'
export const { GET, POST } = SolidStartAuth(auth)
// Client: use createSolidAuth() or useAuth()import { createHandler } from '@rttnd/gau/core'
const handler = createHandler(auth)
Bun.serve({ fetch: handler })Currently supports Drizzle ORM with:
- SQLite (better-sqlite3, libSQL/Turso)
- PostgreSQL (pg, pglite)
- MySQL (planned)
Memory adapter available for testing.
Built-in: GitHub, Google, Discord, Facebook, Microsoft
Each provider implements:
interface OAuthProvider {
id: string
getAuthorizationUrl: (state, codeVerifier, options) => any
validateCallback: (code, codeVerifier, redirectUri) => any
refreshAccessToken?: (refreshToken) => any
}Special handling for desktop and mobile apps:
- Deep linking callback via custom URI scheme
- Token-based session strategy
- Works with
@tauri-apps/apiand plugins
*.svelte.ts- Svelte 5 runes files- Test files in
packages/gau/test/mirror src structure - Examples in
packages/example-*
Uses Vitest with projects:
fast- Quick unit tests (SQLite)pg- PostgreSQL integration tests