nuxthub-better-auth Template

repository·main·Indexed 41 days ago

https://github.com/atinux/nuxthub-better-auth

A Nuxt 4 authentication template integrating NuxtHub, Better Auth, and Nuxt UI. Designed for high-performance deployment on Cloudflare Workers with D1 or Vercel with Turso using a unified SQLite schema. Includes configurations for GitHub OAuth, role-based access control (RBAC) via the admin plugin, and server-side access control using requireUserSession.

Tokens
2.8K
Snippets
9
Records
12
Agent score
100%

What's inside nuxthub-better-auth

  1. Use Nuxt Better Auth session and API patterns

    main

    When building with this template, follow these Nuxt-specific patterns:

    • Session Management: Use useUserSession() to access the shared, SSR-hydrated session. Do not copy the session into another store or a module-level ref.
    • Data Fetching: The linked-account useFetch automatically forwards cookies during SSR and uses a user-specific key.
    • Server-side Access Control: When creating private API handlers, use requireUserSession(event) to enforce access on the server.
    • UI State: Use local ref state for form inputs. Use action composables to manage pending and error states.
  2. Run the NuxtHub × Better Auth template locally

    main

    To run the project on your local machine using Node 22.19+, 24.11+, or 26+ and Corepack:

    1. Setup Environment Variables: Copy .env.example to .env.
    2. Generate Auth Secret: Generate a 32-byte hex string and assign it to NUXT_BETTER_AUTH_SECRET in your .env file.
      node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"
    3. Configure Local URL: Ensure NUXT_PUBLIC_SITE_URL=http://localhost:3000 is set.
    4. Initialize Database: Use local SQLite by leaving Cloudflare and Turso variables empty.
    5. Start Development:
      corepack enable
      pnpm install
      pnpm db:migrate
      pnpm dev

    Local database is stored in .data/db/sqlite.db.

    cp .env.example .env
    node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"
    corepack enable
    pnpm install
    pnpm db:migrate
    pnpm dev
  3. Enable optional demo login buttons

    main

    To provide quick-login buttons for a disposable hosted demo:

    1. Create Demo Users: Manually create user@nuxthub.demo and admin@nuxthub.demo via the sign-up form using the password nuxthub-demo.
    2. Set Admin Role: Update the role field to admin for the admin account in the database.
    3. Enable Flag: Set NUXT_PUBLIC_DEMO_ACCOUNTS_ENABLED=true in your runtime environment.

    Warning: This flag only shows the buttons; it does not create the accounts. Do not use this for real applications.

  4. Deploy to Cloudflare Workers with D1

    main

    To deploy using Cloudflare D1, follow these steps:

    1. Create D1 Database:
      pnpm exec wrangler login
      pnpm exec wrangler d1 create nuxthub-better-auth
    2. Configure Environment: Set NUXT_HUB_CLOUDFLARE_DATABASE_ID to the ID returned by the command above. Update the Worker name in nuxt.config.ts.
    3. Build and Migrate:
      pnpm build:cloudflare
      pnpm exec wrangler d1 migrations apply DB --config .output/server/wrangler.json --remote
    4. Deploy and Set Secrets:
      pnpm exec wrangler deploy --config .output/server/wrangler.json --var NUXT_PUBLIC_SITE_URL:https://your-worker.workers.dev
      pnpm exec wrangler secret put NUXT_BETTER_AUTH_SECRET --config .output/server/wrangler.json
      Note: You must enter the secret when prompted. The app is not ready for auth traffic until the secret is set.

    Important: NuxtHub generates the Wrangler config with the DB binding. You must pass this config explicitly to D1 commands.

    pnpm exec wrangler login
    pnpm exec wrangler d1 create nuxthub-better-auth
    pnpm build:cloudflare
    pnpm exec wrangler d1 migrations apply DB --config .output/server/wrangler.json --remote
    pnpm exec wrangler deploy --config .output/server/wrangler.json --var NUXT_PUBLIC_SITE_URL:https://your-worker.workers.dev
    pnpm exec wrangler secret put NUXT_BETTER_AUTH_SECRET --config .output/server/wrangler.json
  5. Deploy to Vercel with Turso

    main

    To deploy using Vercel and Turso:

    1. Link and Integrate:
      pnpm dlx vercel@latest link
      pnpm dlx vercel@latest integration add tursocloud --plan starter --name nuxthub-better-auth-db
    2. Configure Environment: The integration provides TURSO_DATABASE_URL and TURSO_AUTH_TOKEN. Ensure NUXT_HUB_CLOUDFLARE_DATABASE_ID is unset.
    3. Set Production Variables:
      pnpm dlx vercel@latest env add NUXT_BETTER_AUTH_SECRET production
      pnpm dlx vercel@latest env add NUXT_PUBLIC_SITE_URL production
    4. **Migrate and Deploy**:
       ```bash
    pnpm dlx vercel@latest env run -e production -- env -u VERCEL -u VERCEL_ENV pnpm db:migrate
    pnpm dlx vercel@latest deploy --prod

    Note on Migrations: The env -u flags are used to prevent the migration command from being treated as a Vercel build, allowing it to access Turso credentials at runtime.

    Note on URLs: For OAuth previews, use a stable preview origin and register its callback with GitHub. NUXT_PUBLIC_SITE_URL must be set to the preview's HTTPS origin.

    pnpm dlx vercel@latest link
    pnpm dlx vercel@latest integration add tursocloud --plan starter --name nuxthub-better-auth-db
    pnpm dlx vercel@latest env add NUXT_BETTER_AUTH_SECRET production
    pnpm dlx vercel@latest env add NUXT_PUBLIC_SITE_URL production
    pnpm dlx vercel@latest env run -e production -- env -u VERCEL -u VERCEL_ENV pnpm db:migrate
    pnpm dlx vercel@latest deploy --prod
  6. Deploy using Node with local SQLite

    main

    To run the application in a Node environment using a local SQLite file:

    1. Migrate: pnpm db:migrate
    2. Build: pnpm build:node
    3. Run: node --env-file=.env .output/server/index.mjs

    Requirements:

    • Set NUXT_PUBLIC_SITE_URL to your HTTPS origin.
    • Persist the .data/db/sqlite.db file across releases.
    • Run behind a trusted reverse proxy that forwards a reliable client IP for rate limiting.
    pnpm db:migrate
    pnpm build:node
    node --env-file=.env .output/server/index.mjs
  7. Configure GitHub OAuth

    main

    To enable GitHub authentication:

    1. Create GitHub OAuth App: Set the local callback URL to http://localhost:3000/api/auth/callback/github (or your production HTTPS equivalent).
    2. Configure Environment Variables:
      • NUXT_GITHUB_CLIENT_ID
      • NUXT_GITHUB_CLIENT_SECRET
      • NUXT_PUBLIC_GITHUB_AUTH_ENABLED=true

    Security Note: Store the client secret as a Worker secret or a private Vercel environment variable. Never include it in public runtime config. If migrating from a previous deployment, rename GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET to the NUXT_ prefixed versions.

  8. Configure client-side authentication with defineClientAuth

    main

    Use defineClientAuth from @nuxtjs/better-auth/config to configure the client-side authentication instance. This function accepts an options object where you can register plugins to extend the client's capabilities, such as handling anonymous users or managing role-based access control (RBAC).

    import { defineClientAuth } from '@nuxtjs/better-auth/config'
    import { adminClient, anonymousClient } from 'better-auth/client/plugins'
    import { demoAccess, demoAdminRole, demoUserRole } from '#shared/auth-access'
    
    export default defineClientAuth({
      plugins: [
        anonymousClient(),
        adminClient({
          ac: demoAccess,
          roles: {
            user: demoUserRole,
            admin: demoAdminRole,
          },
        }),
      ],
    })
  9. Configure the admin plugin for role-based access control

    main

    The admin plugin from better-auth/plugins can be added to the plugins array in your defineServerAuth configuration. It allows you to manage administrative privileges and roles.

    Key options for the admin plugin:

    • ac: Access control configuration (e.g., demoAccess).
    • roles: An object mapping role names (like user or admin) to their respective role definitions (e.g., demoUserRole, demoAdminRole).
    import { admin } from 'better-auth/plugins'
    
    // Inside defineServerAuth plugins array:
    admin({
      ac: demoAccess,
      roles: {
        user: demoUserRole,
        admin: demoAdminRole,
      },
    })
  10. Configure server-side authentication with defineServerAuth

    main

    Use defineServerAuth to configure your authentication server. This function accepts a callback that receives runtimeConfig, allowing you to dynamically configure providers based on your Nuxt environment variables.

    Supported configuration sections include:

    • emailAndPassword: Enable or disable email/password authentication via the enabled boolean.
    • socialProviders: Define OAuth providers (e.g., github) using credentials from runtimeConfig.
    • rateLimit: Configure rate limiting. Set enabled: true and specify storage: 'database' to use your database for tracking limits.
    • plugins: An array of Better Auth plugins to extend functionality (e.g., admin, anonymous).
    import { defineServerAuth } from '@nuxtjs/better-auth/config'
    import { admin, anonymous } from 'better-auth/plugins'
    
    export default defineServerAuth(({ runtimeConfig }) => ({
      emailAndPassword: {
        enabled: true,
      },
      socialProviders: runtimeConfig.githubClientId && runtimeConfig.githubClientSecret
        ? {
            github: {
              clientId: runtimeConfig.githubClientId,
              clientSecret: runtimeConfig.githubClientSecret,
            },
          }
        : undefined,
      rateLimit: {
        enabled: true,
        storage: 'database',
      },
      plugins: [
        anonymous(),
        admin({
          ac: demoAccess,
          roles: {
            user: demoUserRole,
            admin: demoAdminRole,
          },
        }),
      ],
    }))
  11. Configure the adminClient plugin

    main

    The adminClient plugin allows for administrative capabilities on the client side. It requires an options object with the following keys:

    • ac: An access control configuration (e.g., demoAccess).
    • roles: An object mapping role names to their respective role definitions (e.g., { user: demoUserRole, admin: demoAdminRole }).
    adminClient({
      ac: demoAccess,
      roles: {
        user: demoUserRole,
        admin: demoAdminRole,
      },
    })