CodeWorlds
Powrót do kolekcji
Przewodnik17 min czytaniaZespół CodeWorlds

Better Auth, uwierzytelnianie na własnym serwerze

Better Auth trzyma konta użytkowników w Twojej bazie zamiast u dostawcy. Wtyczki, organizacje, dwuskładnikowe logowanie i koszt, który za to płacisz.

Better Auth, uwierzytelnianie na własnym serwerze

Better Auth to biblioteka uwierzytelniania dla TypeScriptu, która działa w Twoim procesie i zapisuje konta w Twojej bazie. Bieżąca wersja to 1.7.1, licencja to MIT, a repozytorium better-auth/better-auth ma około 29,6 tysiąca gwiazdek. Nie ma tu opłaty od aktywnego użytkownika, za to utrzymanie i bezpieczeństwo zostają po Twojej stronie.

Czym różni się od usługi hostowanej

Usługi pokroju Clerk czy Auth0 przejmują całą warstwę tożsamości. Użytkownik trafia na ich domenę albo na ich komponent, one wystawiają token, one trzymają tabelę kont, a Twoja aplikacja odbiera gotowy identyfikator. Rachunek rośnie razem z liczbą aktywnych użytkowników, bo taki jest model rozliczenia w tej kategorii narzędzi.

Better Auth ustawia tę granicę zupełnie inaczej. Instalujesz zależność, podpinasz jeden handler pod ścieżkę /api/auth/* i podajesz połączenie do bazy. Od tej chwili tabele user, session, account i verification leżą obok Twoich własnych tabel, a hasła oraz tokeny sesji przechodzą wyłącznie przez Twój proces. Na zewnątrz idą tylko te żądania, które sam zainicjujesz w stronę dostawcy logowania społecznościowego.

Ten układ ma dwie strony i obie trzeba zobaczyć przed decyzją. Po stronie zysków masz pełną własność danych, brak opłaty skalującej się z liczbą kont oraz możliwość dopisania kolumny do tabeli użytkownika bez proszenia kogokolwiek o zgodę. Zapytania łączące konto z resztą modelu domenowego robisz zwykłym złączeniem w bazie, a nie przez interfejs programistyczny dostawcy z limitem żądań.

Po stronie kosztów jest to, o czym łatwo zapomnieć na etapie prototypu. Aktualizacje bezpieczeństwa musisz wdrażać sam i w rozsądnym czasie. Monitoring prób logowania, rotacja sekretów, obsługa zgłoszeń o przejętym koncie, zgodność z wymaganiami audytora klienta korporacyjnego, to wszystko przechodzi na Twój zespół. Dostawca hostowany daje raport z audytu bezpieczeństwa, który wystarczy podać dalej. Przy własnej instalacji nie masz czego podać.

Skala projektu jest przyzwoita jak na bibliotekę, która powstała w maju 2024 roku. Rejestr npm podaje około 5,9 miliona pobrań w tygodniu kończącym się 19 sierpnia 2026 roku, repozytorium nie jest zarchiwizowane, a ostatni commit pochodzi z dnia pisania tego tekstu. Otwartych zgłoszeń jest jednak około sześciuset sześćdziesięciu, co przy takim tempie rozwoju mówi tyle, że lista rzeczy do zrobienia rośnie równie szybko jak sama biblioteka.

Instalacja, wersja i licencja

Sprawa licencji wygląda tu prosto, choć akurat w tej kategorii bibliotek prosta bywa rzadko. Sprawdziłem trzy źródła i wszystkie mówią to samo. Plik LICENSE.md w repozytorium zawiera tekst MIT z notą praw autorskich Bereketa Engidy od 2024 roku. Pole license w metadanych pakietu w rejestrze npm ma wartość MIT. Paczka opublikowana dla wersji 1.7.1, rozpakowana i przeczytana w środku, niesie ten sam tekst MIT. Interfejs GitHuba również raportuje MIT. Nie ma tu rozjazdu, który potrafi zaskoczyć przy audycie zależności w innych projektach.

Sama instalacja to jedno polecenie, po którym potrzebujesz jeszcze sekretu i adresu bazowego aplikacji.

Code
Bash
npm install better-auth

# wygenerowanie sekretu poleceniem z narzędzia wiersza poleceń
npx @better-auth/cli@latest secret

# minimalny plik .env
# BETTER_AUTH_SECRET=wygenerowana_wartosc
# BETTER_AUTH_URL=http://localhost:3000

Nazwy zmiennych środowiskowych, które biblioteka odczytuje samodzielnie, to BETTER_AUTH_SECRET, BETTER_AUTH_URL oraz BETTER_AUTH_TRUSTED_ORIGINS. Jest też BETTER_AUTH_SECRETS, przeznaczona do rotacji, gdzie podajesz listę wpisów w formacie <wersja>:<sekret> rozdzielonych przecinkami. Pierwszy wpis jest bieżący, pozostałe służą do odczytu starych podpisów, więc rotacja nie unieważnia wszystkich sesji naraz.

Jeśli sekretu nie ustawisz, biblioteka w środowisku deweloperskim sięga po wartość domyślną, natomiast w produkcji rzuca wyjątek z jednoznacznym komunikatem. To dobre zachowanie, ale ma skutek uboczny: sesje wytworzone lokalnie nie przeniosą się na środowisko produkcyjne, bo podpisano je innym kluczem. Ostrzeżenie o zbyt krótkim sekrecie pojawia się poniżej trzydziestu dwóch znaków.

Konfiguracja serwera mieszka zwykle w pliku auth.ts i jest jednym wywołaniem funkcji.

Code
TypeScript
import { betterAuth } from 'better-auth'
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
import { db } from './db'
import * as schema from './db/schema'

export const auth = betterAuth({
  appName: 'moja-aplikacja',
  baseURL: process.env.BETTER_AUTH_URL,
  basePath: '/api/auth',
  secret: process.env.BETTER_AUTH_SECRET,
  database: drizzleAdapter(db, {
    provider: 'pg',
    schema,
    usePlural: false,
    camelCase: true
  }),
  emailAndPassword: {
    enabled: true,
    minPasswordLength: 8,
    maxPasswordLength: 128,
    requireEmailVerification: true,
    autoSignIn: true,
    revokeSessionsOnPasswordReset: true,
    sendResetPassword: async ({ user, url }) => {
      await wyslijMail(user.email, url)
    }
  },
  socialProviders: {
    github: {
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!
    }
  },
  session: {
    expiresIn: 60 * 60 * 24 * 7,
    updateAge: 60 * 60 * 24,
    freshAge: 60 * 60 * 24,
    cookieCache: { enabled: true, maxAge: 5 * 60 }
  },
  trustedOrigins: ['https://moja-aplikacja.pl'],
  telemetry: { enabled: false }
})

Wartości podane wyżej dla sekcji session to jednocześnie wartości domyślne, więc możesz je pominąć. Sesja żyje siedem dni, odświeża się nie częściej niż raz dziennie, a przez dobę od zalogowania uchodzi za świeżą, co ma znaczenie przy operacjach wrażliwych w rodzaju usunięcia konta. Bufor sesji w ciasteczku ma domyślnie pięć minut i jest wyłączony, dopóki go nie włączysz.

Zależności równorzędne są w komplecie oznaczone jako opcjonalne, więc menedżer pakietów nie zmusi Cię do instalowania niczego zbędnego. Na liście są next, react, vue, svelte, solid-js, @sveltejs/kit, @tanstack/react-start, a także sterowniki bazodanowe pg, mysql2, mongodb i better-sqlite3. Wybierasz tylko to, czego faktycznie używasz.

Schemat bazy i narzędzie wiersza poleceń

Rdzeń biblioteki potrzebuje czterech tabel. user przechowuje tożsamość, session aktywne sesje, account powiązania z dostawcami zewnętrznymi oraz hasło, a verification tokeny jednorazowe do weryfikacji adresu i resetu hasła. Piąta tabela, rateLimit, pojawia się dopiero wtedy, gdy ograniczanie liczby żądań przełączysz na przechowywanie w bazie.

Wtyczki dokładają własne tabele. Dwuskładnikowe logowanie dodaje twoFactor z polami secret, backupCodes, verified, failedVerificationCount i lockedUntil. Wtyczka organizacji dokłada organization, member, invitation, a przy włączonych zespołach także team i teamMember, natomiast przy dynamicznym systemie ról jeszcze organizationRole.

Schematu nie piszesz ręcznie. Generuje go osobne narzędzie wiersza poleceń, publikowane jako pakiet @better-auth/cli, dziś w wersji 1.4.21 i również na licencji MIT.

Code
Bash
# wygenerowanie pliku schematu na podstawie konfiguracji z auth.ts
npx @better-auth/cli@latest generate --config ./src/auth.ts --output ./src/db/schema.ts

# zastosowanie zmian w bazie, tylko dla wbudowanego adaptera Kysely
npx @better-auth/cli@latest migrate --config ./src/auth.ts

# interaktywne dodanie biblioteki do istniejącego projektu
npx @better-auth/cli@latest init --skip-db --package-manager pnpm

# wypisanie wykrytej konfiguracji, przydatne przy diagnozie
npx @better-auth/cli@latest info

Tu czai się pułapka, o której lepiej wiedzieć zawczasu. Polecenie migrate działa wyłącznie z wbudowanym adapterem Kysely. Przy Prismie i przy Drizzle narzędzie zatrzymuje się i wypisuje komunikat, że schemat trzeba wygenerować poleceniem generate, a następnie zastosować własnym mechanizmem migracji tego narzędzia. To nie jest błąd ani niedopatrzenie, tylko świadoma decyzja: obie te biblioteki mają własną historię migracji, w którą wchodzenie z zewnątrz kończyłoby się rozjazdem stanu.

Dostępne adaptery to Drizzle, Prisma, MongoDB, Kysely oraz pamięciowy do testów. Adapter Drizzle przyjmuje instancję bazy i obiekt konfiguracji z polami provider przyjmującym wartość pg, mysql albo sqlite, a dalej schema, usePlural, camelCase, schemaName, transaction i debugLogs. Jeśli Twoje tabele mają nazwy w liczbie mnogiej albo siedzą w osobnym schemacie bazy, ustawiasz to tutaj zamiast przepisywać wygenerowany plik.

Sekcje user, session, account i verification w konfiguracji pozwalają dopisać do tych tabel własne kolumny oraz zmienić nazwy pól, jeśli musisz dopasować się do konwencji, która obowiązuje w reszcie bazy. To jest ta różnica względem usługi hostowanej, którą docenia się dopiero po kilku miesiącach pracy nad produktem. Numer identyfikacyjny klienta w systemie księgowym, ustawienia powiadomień, znacznik akceptacji regulaminu, wszystko to może leżeć w tej samej tabeli co adres e-mail, a zapytanie łączące te dane jest zwykłym zapytaniem do bazy. W wariancie hostowanym trzymasz zwykle drugą tabelę profilu po swojej stronie i utrzymujesz synchronizację między nią a kontem u dostawcy, a każda rozbieżność między tymi dwoma źródłami prawdy jest błędem, który ktoś kiedyś będzie musiał odtworzyć i naprawić.

Klient, sesja i integracja z Next.js

Po stronie przeglądarki tworzysz klienta funkcją createAuthClient. Import wybierasz zgodnie z frameworkiem, bo biblioteka publikuje osobne warianty pod better-auth/react, better-auth/vue, better-auth/svelte, better-auth/solid oraz better-auth/client dla kodu bez żadnej z tych bibliotek.

TSsrc/lib/auth-client.ts
TypeScript
// src/lib/auth-client.ts
import { createAuthClient } from 'better-auth/react'

export const authClient = createAuthClient({
  baseURL: process.env.NEXT_PUBLIC_APP_URL
})

// src/app/api/auth/[...all]/route.ts
import { toNextJsHandler } from 'better-auth/next-js'
import { auth } from '@/auth'

export const { GET, POST } = toNextJsHandler(auth)

// komponent kliencki
export function Profil() {
  const { data, isPending, error, refetch } = authClient.useSession()

  if (isPending) return <p>Wczytywanie</p>
  if (error) return <p>{error.message}</p>
  if (!data) return <button onClick={() => authClient.signIn.social({ provider: 'github' })}>Zaloguj</button>

  return (
    <div>
      <span>{data.user.email}</span>
      <button onClick={() => authClient.signOut().then(() => refetch())}>Wyloguj</button>
    </div>
  )
}

Metody klienta odwzorowują ścieżki punktów końcowych. Ścieżce /sign-in/email odpowiada authClient.signIn.email, ścieżce /sign-up/email odpowiada authClient.signUp.email, a /revoke-sessions odpowiada authClient.revokeSessions. Hook useSession zwraca obiekt z polami data, isPending, isRefetching, error oraz funkcją refetch.

Po stronie serwera sesję odczytujesz przez auth.api.getSession, przekazując nagłówki żądania. Ten punkt końcowy wymaga nagłówków jawnie i przyjmuje dwa parametry zapytania, disableCookieCache oraz disableRefresh, które przydają się wtedy, gdy potrzebujesz stanu prosto z bazy zamiast z bufora w ciasteczku.

W Next.js handler podpinasz przez toNextJsHandler, który zwraca funkcje dla metod GET, POST, PATCH, PUT i DELETE. Do tablicy plugins w konfiguracji serwera dokładasz jeszcze nextCookies(), i to musi być ostatnia pozycja tej tablicy, bo wtyczka dopisuje ciasteczka w zaczepie wykonywanym po pozostałych.

Wtyczki: dwuskładnikowe logowanie i organizacje

System wtyczek jest tym, co odróżnia tę bibliotekę od prostych opakowań na sesję. W paczce dla wersji 1.7.1 znajduje się dwadzieścia sześć katalogów wtyczek. Poza opisanymi niżej są tam między innymi admin, magic-link, email-otp, phone-number, username, anonymous, multi-session, bearer, jwt, generic-oauth, captcha, device-authorization, one-time-token, haveibeenpwned oraz open-api. Wbudowanych dostawców logowania społecznościowego jest trzydzieści pięć, od Google i GitHuba po Kakao, Naver, Linear i Vercel.

Wtyczka jest jednocześnie zestawem punktów końcowych, fragmentem schematu bazy i rozszerzeniem typów. Dodaje się ją w dwóch miejscach naraz, po stronie serwera i po stronie klienta, inaczej wnioskowanie typów przestaje działać.

Code
TypeScript
// serwer
import { betterAuth } from 'better-auth'
import { twoFactor, organization } from 'better-auth/plugins'
import { createAccessControl } from 'better-auth/plugins/access'

const ac = createAccessControl({
  faktura: ['czytaj', 'wystaw', 'anuluj'],
  projekt: ['czytaj', 'edytuj', 'usun']
})

const ksiegowy = ac.newRole({ faktura: ['czytaj', 'wystaw'] })

export const auth = betterAuth({
  plugins: [
    twoFactor({
      issuer: 'moja-aplikacja',
      skipVerificationOnEnable: false,
      trustDeviceMaxAge: 60 * 60 * 24 * 30,
      accountLockout: {
        enabled: true,
        maxFailedAttempts: 5,
        durationSeconds: 900
      }
    }),
    organization({
      allowUserToCreateOrganization: true,
      organizationLimit: 5,
      creatorRole: 'owner',
      membershipLimit: 100,
      invitationExpiresIn: 60 * 60 * 48,
      cancelPendingInvitationsOnReInvite: true,
      requireEmailVerificationOnInvitation: true,
      ac,
      roles: { ksiegowy },
      teams: { enabled: true, allowRemovingAllTeams: false },
      sendInvitationEmail: async ({ email, organization, invitation }) => {
        await wyslijZaproszenie(email, organization.name, invitation.id)
      }
    })
  ]
})

// klient
import { createAuthClient } from 'better-auth/react'
import { twoFactorClient, organizationClient } from 'better-auth/client/plugins'

export const authClient = createAuthClient({
  plugins: [twoFactorClient(), organizationClient()]
})

Dwuskładnikowe logowanie obsługuje trzy metody: kody czasowe zgodne ze standardem TOTP, kody jednorazowe wysyłane osobnym kanałem oraz kody zapasowe. Punkty końcowe to /two-factor/enable, /two-factor/disable, /two-factor/get-totp-uri, /two-factor/verify-totp, /two-factor/send-otp, /two-factor/verify-otp, /two-factor/generate-backup-codes i /two-factor/verify-backup-code. Wtyczka wnosi własną regułę ograniczania liczby żądań, trzy próby na dziesięć sekund, oraz opcjonalną blokadę konta po ustalonej liczbie nieudanych weryfikacji.

Wtyczka organizacji jest większa i pokrywa całą typową potrzebę aplikacji rozliczanej na firmy. Ma trzydzieści pięć punktów końcowych, w tym tworzenie i usuwanie organizacji, sprawdzanie dostępności identyfikatora tekstowego, ustawianie organizacji aktywnej w sesji, pełny cykl zaproszeń wraz z odrzuceniem i anulowaniem, zarządzanie członkami i ich rolami, zespoły z osobną listą członków oraz dynamiczne role tworzone w czasie działania aplikacji, jeśli włączysz dynamicAccessControl. System uprawnień budujesz funkcją createAccessControl, podając zbiór zasobów i dozwolonych na nich działań, a role są podzbiorem tego zbioru.

Warto pamiętać o jednym: każda wtyczka zmieniająca schemat wymaga ponownego uruchomienia generate i wdrożenia migracji. Dodanie wtyczki wyłącznie w konfiguracji kończy się błędem o brakującej tabeli przy pierwszym żądaniu, które jej dotknie.

Bezpieczeństwo, które przechodzi na Twoją stronę

Hasła są mieszane algorytmem scrypt z parametrami N równym 16384, r równym 16, p równym 1 i długością klucza 64 bajtów, z losową solą o długości szesnastu bajtów. Wynik zapisuje się jako sól i klucz rozdzielone dwukropkiem, oba w zapisie szesnastkowym. Parametry są rozsądne i nie musisz przy nich nic robić, natomiast możesz podmienić cały mechanizm przez emailAndPassword.password z polami hash i verify. To jedyna sensowna droga migracji kont z systemu, który używał innego algorytmu.

Ograniczanie liczby żądań jest domyślnie włączone tylko w produkcji, z oknem dziesięciu sekund i limitem stu żądań. Domyślne przechowywanie licznika to pamięć procesu, a to jest miejsce, w którym najwięcej wdrożeń traci ochronę bez świadomości, że ją traci. W środowisku bezserwerowym albo za modułem równoważenia obciążenia każda instancja liczy osobno, więc realny limit mnoży się przez liczbę instancji. Rozwiązaniem jest przełączenie na bazę albo na pamięć podręczną wskazaną w secondaryStorage, na przykład na Redisa.

Code
TypeScript
export const auth = betterAuth({
  rateLimit: {
    enabled: true,
    window: 10,
    max: 100,
    storage: 'secondary-storage',
    customRules: {
      '/sign-in/email': { window: 60, max: 5 },
      '/request-password-reset': { window: 300, max: 3 }
    }
  },
  advanced: {
    ipAddress: {
      ipAddressHeaders: ['cf-connecting-ip', 'x-forwarded-for'],
      disableIpTracking: false
    }
  },
  emailAndPassword: {
    enabled: true,
    password: {
      hash: async (haslo) => wlasnyHash(haslo),
      verify: async ({ hash, password }) => wlasnaWeryfikacja(hash, password)
    }
  }
})

Zarządzanie sesjami i powiązanymi kontami dostajesz w rdzeniu, bez sięgania po wtyczki. Punkty końcowe /list-sessions, /revoke-session, /revoke-other-sessions i /revoke-sessions wystarczają, żeby zbudować ekran z listą urządzeń oraz przycisk wylogowujący wszędzie poza bieżącą przeglądarką, czyli dokładnie to, czego oczekuje użytkownik po zmianie hasła. Powiązania z dostawcami zewnętrznymi obsługują /link-social, /list-accounts i /unlink-account, a zasady łączenia kont po adresie e-mail ustawia się w sekcji account.accountLinking. To ostatnie jest miejscem, na które trzeba uważać, bo automatyczne łączenie konta hasłowego z kontem społecznościowym po samym adresie jest wygodne i jednocześnie bywa drogą do przejęcia konta, jeśli dostawca nie potwierdza adresu w sposób, któremu można zaufać.

Telemetria jest domyślnie wyłączona, pole telemetry.enabled ma wartość false i nie zmienia się bez Twojej decyzji. To rzecz, którą audytor sprawdzi, więc dobrze, że odpowiedź jest jednoznaczna.

Reszta odpowiedzialności jest tam, gdzie ją postawił model wdrożenia. Śledzenie wydań, czytanie zgłoszeń bezpieczeństwa, konfiguracja nagłówków, wykrywanie ataków słownikowych na konkretne konta, procedura odzyskiwania dostępu, przechowywanie kopii zapasowych bazy z hasłami. Nic z tego nie robi się samo i nikt nie przyśle Ci powiadomienia, że czas zaktualizować zależność. Jeśli w zespole nie ma nikogo, kto weźmie to na siebie, usługa hostowana wychodzi taniej niezależnie od rachunku.

Better Auth a alternatywy

Ceny w tabeli pochodzą ze stron cennikowych dostawców sprawdzonych 20 sierpnia 2026 roku i dotyczą wariantów samoobsługowych.

NarzędzieModel uruchomieniaGdzie leżą kontaRozliczenieGłówne ograniczenie
Better AuthZależność w Twoim procesieTwoja bazaKoszt serwera i bazy, bez opłaty od użytkownikaUtrzymanie i bezpieczeństwo po Twojej stronie
ClerkUsługa hostowanaInfrastruktura dostawcyDarmowo do 50 000 użytkowników powracających, Pro 25 USD miesięcznie, nadwyżka od 0,02 USD za użytkownikaRachunek rośnie razem z bazą kont
Auth0Usługa hostowanaInfrastruktura dostawcyPlan darmowy do 25 000 aktywnych miesięcznie, Essentials od 35 USD, Professional od 240 USDCena bazowa planów płatnych obejmuje 500 użytkowników
KindeUsługa hostowanaInfrastruktura dostawcyPlan darmowy do 10 500 aktywnych miesięcznie, Pro 25 USD, dodatkowy użytkownik 0,0175 USDProwizja 0,7 procent od transakcji przy module rozliczeń
Supabase AuthUsługa zarządzana albo własny hostingProjekt Supabase, Twój albo hostowanyPlan darmowy do 50 000 aktywnych miesięcznie, Pro od 25 USD ze 100 000 w cenie, potem 0,00325 USD za użytkownikaWiąże uwierzytelnianie z resztą platformy

Z tej tabeli wynika prosty podział. Jeśli masz mało użytkowników i mało czasu, usługa hostowana jest tańsza, bo płacisz kwotę bliską zeru i nie utrzymujesz niczego. Jeśli masz dużo użytkowników o niskiej wartości jednostkowej, na przykład konta darmowe w produkcie z modelem freemium, opłata za aktywnego użytkownika staje się pozycją, która potrafi przewyższyć koszt całej reszty infrastruktury. Jeśli obowiązuje Cię wymóg trzymania danych osobowych we własnej jurysdykcji albo we własnej sieci, wybór zawęża się do dwóch ostatnich wierszy tabeli.

Tabela pomija jeszcze jeden wariant, który wygląda jak Better Auth, ale nim nie jest. SuperTokens też pozwala trzymać konta u siebie, tyle że nie jako zależność w Twoim procesie, lecz jako osobną usługę: rdzeń w kontenerze, biblioteka w backendzie i biblioteka we frontendzie, z wymogiem zgodnych wersji między nimi. Za tę złożoność dostajesz gotowy panel i dojrzały zestaw funkcji. Dwie rzeczy trzeba jednak wiedzieć przed decyzją: katalog ee w repozytorium ma osobną licencję zastrzeżoną, a osiem funkcji wymienionych w kodzie rdzenia jako płatne, w tym wielodostępność, logowanie wieloskładnikowe i logowanie do panelu, wymaga klucza licencyjnego również przy hostowaniu u siebie. Bezpłatne konta panelu są ograniczone do trzech.

Typowe błędy

Pierwszy to zapomniany sekret przy pierwszym wdrożeniu. W produkcji biblioteka nie ruszy i to jest dobra wiadomość, gorzej gdy ktoś skopiuje sekret deweloperski do produkcji, żeby zdążyć przed demonstracją. Wtedy klucz podpisujący sesje trafia do repozytorium razem z plikiem konfiguracyjnym.

Drugi to próba użycia polecenia migrate przy Prismie albo Drizzle. Narzędzie wypisuje wtedy komunikat wskazujący prawidłową drogę, ale łatwo go przeoczyć przy uruchomieniu z poziomu skryptu wdrożeniowego, który połyka wyjście. Poprawna kolejność to generate, a potem migracja narzędziem, które trzyma historię schematu.

Trzeci to ograniczanie liczby żądań pozostawione w pamięci procesu przy wdrożeniu wieloinstancyjnym. Objawem jest brak objawów, bo licznik działa i nawet coś blokuje, tylko przy progu przemnożonym przez liczbę instancji. Sprawdzenie zajmuje minutę: wyślij serię żądań i policz, ile przeszło zanim pojawiła się odpowiedź z kodem 429.

Czwarty to wtyczka dodana tylko po jednej stronie. Serwer bez wtyczki zwraca kod 404 dla ścieżki, której klient używa, a klient bez wtyczki po prostu nie ma metody, którą chcesz wywołać. Komunikat błędu w drugim przypadku pochodzi z TypeScriptu i jest czytelny, w pierwszym trafia dopiero na produkcję.

Piąty dotyczy Next.js i kolejności w tablicy plugins. Wtyczka nextCookies musi stać na końcu, bo działa w zaczepie wykonywanym po pozostałych i dopisuje nagłówki ustawiające ciasteczka. Postawiona wcześniej powoduje, że logowanie kończy się powodzeniem po stronie serwera, a przeglądarka nie dostaje sesji.

Szósty to brak wpisu w trustedOrigins, kiedy front stoi na innej domenie niż serwer uwierzytelniania. Żądania są wtedy odrzucane na etapie sprawdzania źródła, a komunikat nie zawsze prowadzi wprost do przyczyny. Listę można podać w konfiguracji albo w zmiennej środowiskowej BETTER_AUTH_TRUSTED_ORIGINS.

Siódmy to traktowanie wyniku hooka useSession jako podstawy decyzji o dostępie. To jest stan interfejsu, wygodny do pokazania awatara albo ukrycia przycisku, i nic więcej. Każda decyzja o dostępie do danych musi zapaść po stronie serwera na podstawie auth.api.getSession. Dochodzi do tego bufor w ciasteczku: przy włączonym cookieCache unieważnienie sesji staje się widoczne dopiero po wygaśnięciu bufora, domyślnie po pięciu minutach.

FAQ

Czy Better Auth wymaga konkretnej bazy danych?

Nie. Adaptery obejmują Drizzle, Prismę, MongoDB oraz Kysely, a Kysely obsługuje PostgreSQL, MySQL i SQLite. Jest też adapter pamięciowy do testów. Jeśli używasz czegoś spoza tej listy, adapter piszesz sam, implementując interfejs operacji na rekordach.

Czy da się przenieść istniejące konta z innego systemu?

Da się, pod warunkiem że masz dostęp do skrótów haseł. Wstawiasz rekordy do tabel user i account, a algorytm sprawdzania podmieniasz przez emailAndPassword.password, żeby akceptował stary format. Konta oparte wyłącznie na logowaniu społecznościowym przenosi się prościej, bo wystarczy powiązanie identyfikatora dostawcy z użytkownikiem.

Czy biblioteka wysyła jakieś dane telemetryczne?

Domyślnie nie. Pole telemetry.enabled ma wartość false i wymaga jawnego włączenia. Osobny pakiet telemetryczny znajduje się wśród zależności, ale bez tej zgody nic nie wysyła.

Czy Better Auth nadaje się do środowiska bezserwerowego?

Nadaje się, natomiast dwie rzeczy wymagają wtedy zmiany domyślnych ustawień. Ograniczanie liczby żądań trzeba przenieść z pamięci procesu na bazę albo na pamięć podręczną, a przy krótkich cyklach życia funkcji warto rozważyć włączenie bufora sesji w ciasteczku, żeby zbić liczbę zapytań do bazy przy każdym żądaniu.

Ile pracy wymaga własne uwierzytelnianie w porównaniu z usługą hostowaną?

Pierwsze uruchomienie zajmuje porównywalnie mało czasu w obu wariantach, różnica pojawia się później. Przy usłudze hostowanej nie utrzymujesz nic i dostajesz gotowy raport z audytu bezpieczeństwa. Przy własnej instalacji odpowiadasz za aktualizacje, monitoring i procedury odzyskiwania dostępu, co realnie oznacza kilka godzin miesięcznie i jedną osobę, która to obserwuje.

Dokumentację znajdziesz na stronie projektu, kod źródłowy w repozytorium na GitHubie, a metadane opublikowanej paczki w rejestrze npm.

Czytaj dalej

Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie