Better Auth
How Better Auth is used for authentication.
This project uses Better Auth as its core authentication library. It provides a flexible foundation for handling user sessions, credentials, social logins, and more.
Core Concepts
- Adapter Pattern: Better Auth uses adapters to connect to databases. This project utilizes the
prismaAdapterconfigured insrc/server/auth/index.ts. - Plugins: Functionality like admin features, username handling, and third-party integrations (like Polar) are added via plugins. This project uses:
adminplugin: For user management, impersonation, etc.usernameplugin: Allows sign-in/sign-up using a username in addition to email.openAPIplugin: Generates an OpenAPI reference for auth routes at/api/auth/reference.polarplugin (via@polar-sh/better-auth): Integrates Polar for payments and subscriptions.
- Procedures: tRPC procedures (
publicProcedure,protectedProcedure,adminProcedureinsrc/server/api/trpc.ts) leverage Better Auth's session context (ctx.session) to control API access. - Configuration: The main configuration happens within the
betterAuth({...})call insrc/server/auth/index.ts.
Configuration via Environment Variables
Several aspects of Better Auth's behavior can be controlled via environment variables:
Required Core Variables:
BETTER_AUTH_SECRET: A secret string used for signing session tokens. Must be set for production.NEXT_PUBLIC_APP_URL: The absolute URL of your application (e.g.,https://yourapp.com). This is used by Better Auth for constructing callback URLs. Defaults tohttp://localhost:3000if not set explicitly, but should be set for production.
Optional Feature Toggles (Defaults Shown):
NEXT_PUBLIC_AUTH_ENABLE_EMAIL_PASSWORD_AUTHENTICATION=true: Enables or disables the standard email/password login and signup functionality.AUTH_ENABLE_CHANGE_EMAIL=false: Enables or disables the built-in (but currently basic) flow for users to change their email address.AUTH_AUTO_SIGN_IN_AFTER_VERIFICATION=true: If email verification is enabled (NEXT_PUBLIC_AUTH_ENABLE_EMAIL_VERIFICATION=true), setting this totruewill automatically sign the user in after they successfully click the verification link. If set tofalse, they will need to sign in manually after verifying their email.NEXT_PUBLIC_AUTH_ENABLE_EMAIL_VERIFICATION=true: Toggles whether email verification is required after signing up with email/password.
These variables are defined in src/env/schemas and should be set in your .env file.
Server-Side Usage (tRPC)
Better Auth integrates tightly with tRPC to provide authenticated procedures.
Public vs. Protected Procedures (src/server/api/trpc.ts)
-
publicProcedure: Use this for API endpoints accessible to anyone (logged in or not). Inside a public procedure,ctx.sessionmight benull. Always check forctx.session?.userbefore accessing user data. -
protectedProcedure: Use this for endpoints that require a logged-in user. This procedure automatically verifies the session.- If no valid session exists, it throws an
UNAUTHORIZEDTRPCError. - Inside a protected procedure,
ctx.session.useris guaranteed to exist and be non-nullable. - Accessing User ID: Get the current user's ID directly via
ctx.session.user.id.
- If no valid session exists, it throws an
-
adminProcedure: ExtendsprotectedProcedureand adds a check to ensurectx.session.user.role === 'admin'. Use this for admin-only actions.
Server-Side Session Helper (src/server/auth/index.ts)
-
getServerSession: A cached helper function (cachefrom React) to securely get the current session within Server Components or traditional Next.js API routes (outside of tRPC).
Client-Side Usage
Fetching User Data (src/hooks/useCurrentUser.ts)
-
useCurrentUser()Hook: This is the recommended way to get the current user's full data object (including preferences, role, custom fields) in client components.- It internally calls the
api.user.getCurrentUsertRPC query. - It uses
authClient.useSession()only to enable/disable the query (won't run if not logged in). - Advantage: Leverages React Query for caching, background updates, and cache invalidation. If you update user data with a tRPC mutation, invalidating the
getCurrentUserquery will automatically update the data provided by this hook throughout your app. - Returns
undefinedduring initial loading, error states, or if the user is not logged in.
- It internally calls the
Basic Auth Actions (src/server/auth/client.ts)
authClient: Provides client-side functions for common authentication actions.authClient.useSession(): Hook to get basic session status (logged in/out) and minimal user data (e.g., email). Use this primarily for quickly checking authentication state, not for detailed user profile data (useuseCurrentUserfor that).authClient.signIn.email({...}): Sign in using email and password.authClient.signUp.email({...}): Sign up using email and password (and username if the plugin is active).authClient.signOut(): Log the user out.- These are typically used within forms or UI components (e.g.,
src/app/(landing)/(auth)/signin/signin-form.tsx).
Key Files
src/server/auth/index.ts: The main Better Auth configuration file.src/server/api/trpc.ts: Defines tRPC procedures that use the auth context.src/env.ts: Defines environment variables related to authentication..env.example: Shows placeholders for auth-related environment variables.
Further Reading
For more in-depth information on Better Auth's capabilities and configuration options, refer to the official Better Auth documentation.