@faable/auth-js - v1.7.4
    Preparing search index...

    @faable/auth-js - v1.7.4

    Faable

    auth-js

    An isomorphic JavaScript client for Faable Auth.

    📚 Full documentation at faable.com/docs

    • OAuth social connections (Google, GitHub, …) with PKCE and implicit flows
    • Username + password login
    • Passwordless: email magic link and OTP code
    • Automatic token refresh with cross-tab synchronization via BroadcastChannel
    • Pluggable storage adapters (localStorage, cookies, or custom)
    • Server-side session helpers for Next.js
    npm install @faable/auth-js
    

    Requires Node.js >=22.8 for development. The published bundle runs in any modern browser and in Node/SSR environments.

    import { createClient } from '@faable/auth-js'

    export const auth = createClient({
    domain: '<faableauth_domain>',
    clientId: '<client_id>',
    redirectUri: window.location.origin
    })

    // Trigger a social login
    await auth.signInWithOauthConnection({ connection: 'google' })

    createClient(config) accepts:

    Option Type Description
    domain string Required. Your Faable Auth tenant domain.
    clientId string Required. Application client ID.
    redirectUri string Default callback URL. Falls back to window.location.origin.
    scope string Space-separated scopes. Defaults to openid profile email.
    storage SupportedStorage Custom storage adapter. Defaults to localStorage.
    storageKey string Prefix for the storage key. Final key is ${storageKey}-${clientId}.
    cookieOptions CookieOptions When set, switches storage to the cookie adapter.
    lock LockFunc Custom locking primitive for concurrent refreshes.
    debug boolean Enables verbose logging.
    // Use the default connection configured on the tenant
    await auth.signInWithOauthConnection({})

    // Or pick a specific provider (by name or connection_id)
    await auth.signInWithOauthConnection({
    connection_id: 'conn_01HX…', // preferred when known; falls back to `connection` for legacy tenants
    redirectTo: 'https://app.example.com/callback',
    scopes: 'openid profile email',
    queryParams: { prompt: 'select_account' }
    })

    In browsers the SDK uses the PKCE flow by default and exchanges the code for a session on the callback page. The first call to createClient automatically processes the URL when the user lands back on the redirect target.

    await auth.signInWithUsernamePassword({
    username: 'user@example.com',
    password: '••••••••',
    redirectTo: 'https://app.example.com/callback'
    })
    // Step 1 — request a code or link
    await auth.signInWithPasswordless({
    email: 'user@example.com',
    type: 'code' // or "link"
    })

    // Step 2 — complete the login with the OTP the user received
    const { data, error } = await auth.signInWithOtp({
    username: 'user@example.com',
    otp: '123456'
    })
    await auth.changePassword({ email: 'user@example.com' })
    
    await auth.signOut() // global — all sessions for this user
    await auth.signOut({ scope: 'local' }) // only this device
    // Get the current session (refreshes if needed)
    const {
    data: { session }
    } = await auth.getSession()

    // Subscribe to auth events
    const {
    data: { subscription }
    } = auth.onAuthStateChange((event, session) => {
    // event: INITIAL_SESSION | SIGNED_IN | SIGNED_OUT | TOKEN_REFRESHED | PASSWORD_RECOVERY | USER_UPDATED
    })

    // Stop listening
    subscription.unsubscribe()

    // Force a refresh
    await auth.refreshSession()

    Auth events are broadcast across tabs using BroadcastChannel, so a sign-in or sign-out in one tab is reflected in every other tab using the same storageKey.

    Refresh tokens are sensitive: anyone who reads them can impersonate the user until the token is revoked. The storage you pick decides where they live:

    • localStorage (default) — simple and supports cross-tab sync via BroadcastChannel, but any script running on the same origin can read it. A single XSS lets an attacker exfiltrate the refresh token. Acceptable for low-risk apps and prototypes; not recommended when the surface has third-party scripts, user-generated HTML, or strict compliance requirements.
    • Cookies — required for SSR (server reads them on every request) and the only adapter that lets you scope storage with Secure, SameSite, and Domain. Note that this library writes cookies from JavaScript, so they cannot be marked HttpOnly; an XSS can still read them, but cookies make CSRF and same-site policies enforceable in a way localStorage does not.
    • Custom adapter — use for in-memory storage (tokens lost on reload, safest against XSS), Web Workers, or platform-specific keychains.

    If your app is exposed to untrusted content, prefer cookies with Secure: true and SameSite: "Lax" (or "Strict"), and treat XSS prevention (CSP, escaping, framework guarantees) as a hard requirement regardless of which adapter you pick.

    Used automatically in browsers. No configuration required.

    Useful for SSR setups where the server must read the session from the request.

    import { createClient } from '@faable/auth-js'

    export const auth = createClient({
    domain: '<faableauth_domain>',
    clientId: '<client_id>',
    storage: 'cookie'
    })

    That's it. The adapter sets sensible defaults: Path=/, SameSite=Lax, auto Secure on HTTPS, and a 30-day Max-Age so users stay signed in across browser restarts.

    Use cookieOptions only when you need to override something — e.g. share the session across subdomains:

    createClient({
    domain: '<faableauth_domain>',
    clientId: '<client_id>',
    storage: 'cookie',
    cookieOptions: { domain: '.example.com' }
    })

    Provide any object that implements getItem, setItem, and removeItem (sync or async). Set isServer: true if values may come from an untrusted source such as request cookies.

    const memoryStorage = {
    store: new Map<string, string>(),
    getItem: (k: string) => memoryStorage.store.get(k) ?? null,
    setItem: (k: string, v: string) => void memoryStorage.store.set(k, v),
    removeItem: (k: string) => void memoryStorage.store.delete(k)
    }

    createClient({ domain, clientId, storage: memoryStorage })

    Use cookie storage on the client, then read the session from next/headers on the server:

    // app/page.tsx
    import { cookies } from 'next/headers'
    import { getSessionFromCookies } from '@faable/auth-js'

    export default async function Page() {
    const session = getSessionFromCookies(cookies(), { clientId: '<client_id>' })
    if (!session) return <SignIn />
    return <Dashboard user={session.user} />
    }

    Pass the same clientId you used in createClient. If you also passed a custom storageKey to createClient, mirror it here as { clientId, storageKey } so the helper looks at the same cookie.

    For the full guides, API reference, and dashboard setup walkthroughs visit faable.com/docs.

    See LICENSE.md.