How to create api with better-auth and fastify? #143

Closed
opened 2026-03-13 07:35:07 -05:00 by GiteaMirror · 6 comments
Owner

Originally created by @ruimarcosjoao on GitHub (Oct 25, 2024).

I'm creating an api with fastify and I intend to use better auth for authentication, and this is my code:

import Fastify from 'fastify'
import cors from '@fastify/cors'
import { betterAuth } from 'better-auth'
import Database from 'better-sqlite3'

const fastify = Fastify({ logger: true })

// Configurar CORS
fastify.register(cors, {
  origin: true, // Ajuste conforme necessário para sua aplicação
  credentials: true
})

// Configurar Better Auth
const auth = betterAuth({
  database: new Database('auth.db'),
  emailAndPassword: {
    enabled: true,
  },
  // Adicione outras opções conforme necessário
})

// Rota protegida de exemplo
fastify.get('/protected', async (request, reply) => {
  const session = await auth.api.getSession({
    headers: request.headers,
    query: request.query,
  })

  if (!session) {
    reply.code(401).send({ error: 'Não autorizado' })
    return
  }

  reply.send({ message: 'Rota protegida', user: session.user })
})

// Rota de autenticação
fastify.post('/api/auth/*', async (request, reply) => {
  const response = await auth.handler(request.raw)
  
  reply.status(response.status)
  reply.headers(Object.fromEntries(response.headers.entries()))
  reply.send(await response.text())
})

// Iniciar o servidor
const start = async () => {
  try {
    await fastify.listen({ port: 3000 })
  } catch (err) {
    fastify.log.error(err)
    process.exit(1)
  }
}

start()```
Originally created by @ruimarcosjoao on GitHub (Oct 25, 2024). I'm creating an api with fastify and I intend to use better auth for authentication, and this is my code: ``` ts import Fastify from 'fastify' import cors from '@fastify/cors' import { betterAuth } from 'better-auth' import Database from 'better-sqlite3' const fastify = Fastify({ logger: true }) // Configurar CORS fastify.register(cors, { origin: true, // Ajuste conforme necessário para sua aplicação credentials: true }) // Configurar Better Auth const auth = betterAuth({ database: new Database('auth.db'), emailAndPassword: { enabled: true, }, // Adicione outras opções conforme necessário }) // Rota protegida de exemplo fastify.get('/protected', async (request, reply) => { const session = await auth.api.getSession({ headers: request.headers, query: request.query, }) if (!session) { reply.code(401).send({ error: 'Não autorizado' }) return } reply.send({ message: 'Rota protegida', user: session.user }) }) // Rota de autenticação fastify.post('/api/auth/*', async (request, reply) => { const response = await auth.handler(request.raw) reply.status(response.status) reply.headers(Object.fromEntries(response.headers.entries())) reply.send(await response.text()) }) // Iniciar o servidor const start = async () => { try { await fastify.listen({ port: 3000 }) } catch (err) { fastify.log.error(err) process.exit(1) } } start()```
Author
Owner

@Bekacru commented on GitHub (Dec 17, 2024):

If it works, great! If not, feel free to open another issue with details on what’s not working.

We don’t officially support Fastify right now, but if you get it working, we'd really appreciate a PR for the docs!

@Bekacru commented on GitHub (Dec 17, 2024): If it works, great! If not, feel free to open another issue with details on what’s not working. We don’t officially support Fastify right now, but if you get it working, we'd really appreciate a PR for the docs!
Author
Owner

@rinarakaki commented on GitHub (Apr 8, 2025):

This doesn't work:

Argument of type 'IncomingMessage' is not assignable to parameter of type 'Request'.
  Type 'IncomingMessage' is missing the following properties from type 'Request': cache, credentials, destination, integrity, and 15 more.
@rinarakaki commented on GitHub (Apr 8, 2025): This doesn't work: ``` Argument of type 'IncomingMessage' is not assignable to parameter of type 'Request'. Type 'IncomingMessage' is missing the following properties from type 'Request': cache, credentials, destination, integrity, and 15 more. ```
Author
Owner

@ruimarcosjoao commented on GitHub (Apr 8, 2025):

Use this code above, will work!

import { toNodeHandler } from "better-auth/node";
import fastify from "fastify";

const app = fastify({
  logger: {
    level: env.LOG_LEVEL,
  },
});

app.register((fastify) => {
  const authhandler = toNodeHandler(auth);

  fastify.addContentTypeParser(
    "application/json",
    (_request, _payload, done) => {
      done(null, _payload);
    }
  );

  fastify.all("/api/auth/*", async (request, reply) => {
    await authhandler(request.raw, reply.raw);
  });
});

and add OpenApi() plugin to see the documentation

@ruimarcosjoao commented on GitHub (Apr 8, 2025): Use this code above, will work! ``` ts import { toNodeHandler } from "better-auth/node"; import fastify from "fastify"; const app = fastify({ logger: { level: env.LOG_LEVEL, }, }); app.register((fastify) => { const authhandler = toNodeHandler(auth); fastify.addContentTypeParser( "application/json", (_request, _payload, done) => { done(null, _payload); } ); fastify.all("/api/auth/*", async (request, reply) => { await authhandler(request.raw, reply.raw); }); }); ``` and add OpenApi() plugin to see the documentation
Author
Owner

@ruimarcosjoao commented on GitHub (Apr 8, 2025):

use this for middlefare to protected router

import { auth, UserRole } from "@/lib/auth";
import { FastifyReply, FastifyRequest } from "fastify";

interface AuthenticatedRequest extends FastifyRequest {
  user?: {
    id: string;
    role: UserRole;
  };
}

interface UserWithRole {
  id: string;
  role: string;
}

export async function authenticate(
  request: AuthenticatedRequest,
  requiredRole?: UserRole
) {
  try {
    const session = await auth.api.getSession({
      headers: new Headers(request.headers as any),
    });

    if (!session) {
      return {
        code: "UNAUTHORIZED",
        message: "Usuário não autenticado",
      };
    }

    if (requiredRole && session.user.role !== requiredRole) {
      return {
        code: "UNAUTHORIZED",
        message: "Usuário não tem permissão para acessar este recurso",
      };
    }

    request.user = {
      id: session.user.id,
      role: session.user.role as UserRole,
    };
  } catch (error) {
    return {
      code: "UNAUTHORIZED",
      message: "Erro na autenticação",
    };
  }
}

export function AuthMiddleware(requiredRole?: UserRole) {
  return async (request: AuthenticatedRequest, reply: FastifyReply) => {
    const result = await authenticate(request, requiredRole);

    if (result) {
      return reply.status(401).send(result);
    }
  };
}

@ruimarcosjoao commented on GitHub (Apr 8, 2025): use this for middlefare to protected router ``` ts import { auth, UserRole } from "@/lib/auth"; import { FastifyReply, FastifyRequest } from "fastify"; interface AuthenticatedRequest extends FastifyRequest { user?: { id: string; role: UserRole; }; } interface UserWithRole { id: string; role: string; } export async function authenticate( request: AuthenticatedRequest, requiredRole?: UserRole ) { try { const session = await auth.api.getSession({ headers: new Headers(request.headers as any), }); if (!session) { return { code: "UNAUTHORIZED", message: "Usuário não autenticado", }; } if (requiredRole && session.user.role !== requiredRole) { return { code: "UNAUTHORIZED", message: "Usuário não tem permissão para acessar este recurso", }; } request.user = { id: session.user.id, role: session.user.role as UserRole, }; } catch (error) { return { code: "UNAUTHORIZED", message: "Erro na autenticação", }; } } export function AuthMiddleware(requiredRole?: UserRole) { return async (request: AuthenticatedRequest, reply: FastifyReply) => { const result = await authenticate(request, requiredRole); if (result) { return reply.status(401).send(result); } }; } ```
Author
Owner

@rinarakaki commented on GitHub (Apr 8, 2025):

That helps a lot! Thank you!

@rinarakaki commented on GitHub (Apr 8, 2025): That helps a lot! Thank you!
Author
Owner

@ruimarcosjoao commented on GitHub (Apr 8, 2025):

That helps a lot! Thank you!
Cool, i was the same problem, but now it's solved!

@ruimarcosjoao commented on GitHub (Apr 8, 2025): > That helps a lot! Thank you! Cool, i was the same problem, but now it's solved!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#143