Como Usar a Melhor API de Autenticação para Autenticação Moderna

Ashley Goolam

Ashley Goolam

14 novembro 2025

Como Usar a Melhor API de Autenticação para Autenticação Moderna

A autenticação é a pedra angular de qualquer aplicação web moderna, mas configurá-la continua sendo um dos desafios mais demorados que os desenvolvedores enfrentam. Apresentamos a Better Auth API — uma solução de autenticação agnóstica a frameworks que promete transformar a forma como implementamos o gerenciamento de usuários. Neste guia completo, vamos construir uma aplicação full-stack completa que demonstra o poder e a simplicidade da Better Auth, usando Bun para um desempenho incrivelmente rápido.

💡
Quer uma ótima ferramenta de Teste de API que gera uma linda Documentação de API?

Quer uma plataforma integrada e completa para sua Equipe de Desenvolvedores trabalhar com máxima produtividade?

Apidog atende a todas as suas demandas e substitui o Postman por um preço muito mais acessível!
botão

O que é a Better Auth API?

A Better Auth API é um framework de autenticação moderno e de código aberto, projetado para funcionar perfeitamente em qualquer ambiente JavaScript. Ao contrário das bibliotecas de autenticação tradicionais que o prendem a ecossistemas específicos, a Better Auth oferece uma API unificada que se adapta à sua stack — seja você usando React, Vue, Svelte ou JavaScript puro no frontend, e Node.js, Bun ou Deno no backend. Sua arquitetura baseada em plugins suporta múltiplas estratégias de autenticação, desde e-mail/senha tradicionais até provedores OAuth, passkeys e links mágicos, tudo isso mantendo a segurança de tipos e uma excelente experiência para o desenvolvedor.

better auth

Começando com Better Auth: Pré-requisitos e Configuração do Projeto

Antes de mergulhar no código, certifique-se de ter o seguinte instalado:

vs code ide

Embora esta configuração funcione perfeitamente com npm, demonstraremos o fluxo de trabalho do Bun, que oferece instalação de pacotes 3-5 vezes mais rápida e uma experiência de desenvolvimento mais simplificada.

Construindo um Projeto de Exemplo: Implementação Passo a Passo

Vamos criar um sistema de autenticação prático com um frontend React e um backend Express, completo com persistência de banco de dados.

Passo 1: Configuração do Backend com Express e Drizzle ORM

1. Inicializar o Projeto Backend

Primeiro, crie e entre no seu diretório backend:

mkdir better-auth-backend
cd better-auth-backend
bun init -y

2. Instalar Dependências

Precisaremos do Express para o servidor, Better Auth para autenticação e Drizzle ORM para gerenciamento de banco de dados:

bun add express better-auth drizzle-orm
bun add -D @types/bun @types/express drizzle-kit

3. Configurar Variáveis de Ambiente

Crie um arquivo .env para armazenar configurações sensíveis:

BETTER_AUTH_SECRET=your-secret-key-here # Generate with: openssl rand -base64 32
BETTER_AUTH_URL=http://localhost:3000
DATABASE_URL=local.db

O BETTER_AUTH_SECRET também pode ser gerado no site da better-auth.

4. Criar Esquema de Banco de Dados com Drizzle ORM

Better Auth funciona melhor com Drizzle, que oferece excelente suporte a TypeScript e evita problemas com módulos nativos. Crie src/db/schema.ts:

import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";

export const user = sqliteTable("user", {
  id: text("id").primaryKey(),
  name: text('name').notNull(),
  email: text('email').notNull().unique(),
  emailVerified: integer('email_verified', { mode: 'boolean' }).notNull().default(false),
  image: text('image'),
  createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
  updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull(),
});

export const session = sqliteTable("session", {
  id: text("id").primaryKey(),
  expiresAt: integer('expires_at', { mode: 'timestamp' }).notNull(),
  token: text('token').notNull().unique(),
  createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
  userId: text('user_id').notNull(),
});

export const account = sqliteTable("account", {
  id: text("id").primaryKey(),
  accountId: text('account_id').notNull(),
  providerId: text('provider_id').notNull(),
  userId: text('user_id').notNull(),
  accessToken: text('access_token'),
  refreshToken: text('refresh_token'),
  createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
});

export const verification = sqliteTable("verification", {
  id: text("id").primaryKey(),
  identifier: text('identifier').notNull(),
  value: text('value').notNull(),
  expiresAt: integer('expires_at', { mode: 'timestamp' }).notNull(),
});

5. Configurar Conexão com o Banco de Dados

Crie src/db/index.ts usando a ligação nativa do Bun para SQLite:

import { Database } from "bun:sqlite";
import { drizzle } from "drizzle-orm/bun-sqlite";

const sqlite = new Database("local.db");
export const db = drizzle(sqlite);

6. Configurar Better Auth

Crie src/lib/auth.ts para configurar a Better Auth API:

import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "../db";
import { user, session, account, verification } from "../db/schema";

export const auth = betterAuth({
  database: drizzleAdapter(db, {
    provider: "sqlite",
    schema: {
      user: user,
      session: session,
      account: account,
      verification: verification,
    },
  }),
  emailAndPassword: {
    enabled: true,
  },
  trustedOrigins: ["http://localhost:5173"],
});

7. Criar Servidor Express

Em src/index.ts, monte o handler da Better Auth API:

import express from "express";
import cors from "cors";
import { toNodeHandler } from "better-auth/node";
import { auth } from "./lib/auth";

const app = express();
const PORT = process.env.PORT || 3000;

app.use(
  cors({
    origin: "http://localhost:5173",
    credentials: true,
  })
);

// Mount Better Auth API at /api/auth
app.use("/api/auth", toNodeHandler(auth));
app.use(express.json());

app.get("/api/me", async (req, res) => {
  const session = await auth.api.getSession({
    headers: req.headers,
  });
  
  if (!session) {
    return res.status(401).json({ error: "Unauthorized" });
  }
  
  res.json({ user: session.user });
});

app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
});

8. Executar Migração do Banco de Dados

Crie drizzle.config.ts na raiz do backend:

import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  schema: "./src/db/schema.ts",
  out: "./drizzle",
  dbCredentials: {
    url: "local.db",
  },
});

Execute a migração para criar as tabelas:

bunx drizzle-kit push
estrutura do projeto do servidor backend

Passo 2: Configuração do Frontend com React e Vite

1. Criar Aplicação React

Em um novo terminal, inicialize o frontend:

bun create vite better-auth-frontend --template react-ts
cd better-auth-frontend

2. Instalar Dependências

bun add better-auth

3. Configurar Tailwind CSS (Atualização V4)

O Tailwind CSS v4 exige uma configuração diferente. Instale os novos pacotes:

bun add -D tailwindcss postcss @tailwindcss/postcss

Crie tailwind.config.js na raiz do projeto:

/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

Crie postcss.config.js:

export default {
  plugins: {
    "@tailwindcss/postcss": {},
  },
}

Crie src/index.css:

@import "tailwindcss";

body {
  margin: 0;
  font-family: system-ui, -apple-system, sans-serif;
}

4. Configurar Cliente Better Auth

Crie src/lib/auth-client.ts:

import { createAuthClient } from "better-auth/react";

export const authClient = createAuthClient({
  baseURL: "http://localhost:3000",
});

export const { signIn, signUp, useSession } = authClient;

5. Construir a UI de Autenticação

Substitua src/App.tsx por uma interface de autenticação completa:

import { useState } from 'react';
import { useSession, signIn, signUp } from './lib/auth-client';

function App() {
  const { data: session, isPending } = useSession();
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [name, setName] = useState('');

  const handleSignUp = async (e: React.FormEvent) => {
    e.preventDefault();
    await signUp.email({
      name,
      email,
      password,
      callbackURL: '/',
    });
  };

  const handleSignIn = async (e: React.FormEvent) => {
    e.preventDefault();
    await signIn.email({
      email,
      password,
    });
  };

  const handleSignOut = async () => {
    await authClient.signOut();
  };

  if (isPending) return <div className="flex items-center justify-center min-h-screen">Carregando...</div>;

  return (
    <div className="min-h-screen bg-gray-100 flex items-center justify-center p-4">
      <div className="max-w-md w-full bg-white rounded-lg shadow-md p-6">
        <h1 className="text-2xl font-bold text-center mb-6 text-gray-800">
          Teste da Better Auth API
        </h1>

        {session?.user ? (
          <div className="space-y-4">
            <div className="bg-green-50 p-4 rounded-md">
              <p className="text-green-800 font-semibold">Logado como:</p>
              <p className="text-green-700">{session.user.email}</p>
              <p className="text-green-600 text-sm">{session.user.name}</p>
            </div>
            <button
              onClick={handleSignOut}
              className="w-full bg-red-500 hover:bg-red-600 text-white font-medium py-2 px-4 rounded-md transition"
            >
              Sair
            </button>
          </div>
        ) : (
          <div className="space-y-4">
            <form onSubmit={handleSignUp} className="space-y-3">
              <h2 className="text-lg font-semibold text-gray-700">Cadastrar</h2>
              <input
                type="text"
                placeholder="Nome"
                value={name}
                onChange={(e) => setName(e.target.value)}
                className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
                required
              />
              <input
                type="email"
                placeholder="Email"
                value={email}
                onChange={(e) => setEmail(e.target.value)}
                className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
                required
              />
              <input
                type="password"
                placeholder="Senha"
                value={password}
                onChange={(e) => setPassword(e.target.value)}
                className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
                required
              />
              <button
                type="submit"
                className="w-full bg-green-500 hover:bg-green-600 text-white font-medium py-2 px-4 rounded-md transition"
              >
                Criar Conta
              </button>
            </form>

            <form onSubmit={handleSignIn} className="space-y-3">
              <h2 className="text-lg font-semibold text-gray-700">Entrar</h2>
              <input
                type="email"
                placeholder="Email"
                value={email}
                onChange={(e) => setEmail(e.target.value)}
                className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
                required
              />
              <input
                type="password"
                placeholder="Senha"
                value={password}
                onChange={(e) => setPassword(e.target.value)}
                className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
                required
              />
              <button
                type="submit"
                className="w-full bg-blue-500 hover:bg-blue-600 text-white font-medium py-2 px-4 rounded-md transition"
              >
                Entrar
              </button>
            </form>
          </div>
        )}
      </div>
    </div>
  );
}

export default App;
estrutura do projeto do aplicativo frontend

Passo 3: Testando a Integração

1. Iniciar Servidor Backend

cd better-auth-backend
bun dev
executar o servidor backend better auth

2. Iniciar Desenvolvimento Frontend

cd better-auth-frontend
bun dev
executar o aplicativo frontend better auth

3. Testar Fluxo de Autenticação

sign up or sign in
Informações Corretas
sign in attempt with wrong information
Informações Incorretas
sign out

Principais Benefícios da Better Auth API

A Better Auth API se destaca por várias vantagens convincentes:

Perguntas Frequentes

P1: Posso usar a Better Auth API com npm em vez de Bun?
Resp: Com certeza. Embora este guia utilize o Bun por seus benefícios de desempenho, cada comando tem um equivalente npm. Substitua bun add por npm install, bun dev por npm run dev e bunx por npx. O único código específico do Bun é a importação bun:sqlite, que pode ser substituída por better-sqlite3 para ambientes Node.js.

P2: Por que precisamos do Drizzle ORM? A Better Auth não pode criar tabelas automaticamente?
Resp: A Better Auth segue o princípio do gerenciamento explícito de banco de dados. O Drizzle fornece migrações com segurança de tipos, versionamento de esquema e previne a perda acidental de dados. O comando drizzle-kit push é uma configuração única que lhe dá controle total sobre a evolução do seu banco de dados.

P3: E se eu encontrar o erro "Missing parameter name"?
Resp: Isso ocorre ao usar app.all() com wildcards no Express. A solução é usar app.use("/api/auth", toNodeHandler(auth)) em vez disso. O handler da Better Auth gerencia todas as sub-rotas internamente, então o Express não precisa de correspondência com wildcards.

P4: Como adiciono provedores de autenticação social?
Resp: Habilite os plugins OAuth na sua configuração da Better Auth. Por exemplo, para adicionar o GitHub:

import { betterAuth } from "better-auth";
import { github } from "better-auth/plugins";

export const auth = betterAuth({
  plugins: [
    github({
      clientId: process.env.GITHUB_CLIENT_ID,
      clientSecret: process.env.GITHUB_CLIENT_SECRET,
    })
  ]
});

P5: A Better Auth API está pronta para produção?
Resp: Sim. A Better Auth impulsiona a autenticação para vários produtos SaaS com milhares de usuários. O framework implementa gerenciamento seguro de sessão, proteção CSRF e segue as diretrizes da OWASP. No entanto, sempre audite sua implementação específica e mantenha as dependências atualizadas.

Conclusão

Construir autenticação do zero não é mais necessário com soluções modernas como a Better Auth API. Neste guia, criamos um sistema de autenticação completo — do esquema do banco de dados aos componentes da UI — em poucos minutos! A combinação da flexibilidade da Better Auth, da segurança de tipos do Drizzle ORM e do desempenho do Bun cria uma experiência de desenvolvedor que escala do protótipo à produção.

O processo passo a passo demonstra que a autenticação, embora crítica, não precisa ser complexa. Ao aproveitar a arquitetura de plugins e o design agnóstico de framework da Better Auth, você pode se concentrar na construção de recursos que importam para seus usuários, em vez de lutar com implementações de segurança.

Quer você esteja construindo um projeto pessoal ou uma aplicação empresarial, a Better Auth API fornece a base para uma autenticação segura e escalável que se adapta às suas necessidades — e não o contrário.

💡
Quer uma ótima ferramenta de Teste de API que gera uma linda Documentação de API?

Quer uma plataforma integrada e completa para sua Equipe de Desenvolvedores trabalhar com máxima produtividade?

Apidog atende a todas as suas demandas e substitui o Postman por um preço muito mais acessível!
botão

Pratique o design de API no Apidog

Descubra uma forma mais fácil de construir e usar APIs