Authentication Best Practices with Better Auth
Implementing secure, scalable authentication in your SaaS application
Authentication is one of the most critical aspects of any SaaS application. Get it wrong, and you risk security vulnerabilities and poor user experience. ZeroStarter uses Better Auth, a modern authentication library that makes implementing secure auth straightforward.
Why Better Auth?
Better Auth provides a comprehensive solution for authentication that's:
- Type-safe: Built with TypeScript from the ground up
- Flexible: Supports multiple providers and strategies
- Secure: Implements best practices by default
- Developer-friendly: Simple API with powerful features
Setting Up Authentication
In ZeroStarter, authentication is configured in the packages/auth package:
// packages/auth/src/index.ts
import { betterAuth } from "better-auth"
import { drizzleAdapter } from "better-auth/adapters/drizzle"
export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "postgresql",
}),
emailAndPassword: {
enabled: true,
},
socialProviders: {
github: {
clientId: env.GITHUB_CLIENT_ID,
clientSecret: env.GITHUB_CLIENT_SECRET,
},
},
})Security Best Practices
1. Secure Session Management
Better Auth handles session management securely:
- Uses HTTP-only cookies by default
- Implements CSRF protection
- Supports secure session rotation
- Handles session expiration properly
2. Password Security
When using email/password authentication:
- Passwords are hashed using bcrypt
- Minimum password requirements enforced
- Rate limiting on login attempts
- Protection against brute force attacks
3. OAuth Integration
For social providers like GitHub:
- Secure OAuth 2.0 flow
- Proper token handling
- User profile synchronization
- Account linking support
Frontend Integration
The frontend uses a React hook for authentication:
// web/next/src/lib/auth/client.ts
import { createAuthClient } from "better-auth/react"
export const authClient = createAuthClient({
baseURL: process.env.NEXT_PUBLIC_API_URL,
})
// Usage in components
const { data: session } = useSession()Protected Routes
ZeroStarter demonstrates how to protect routes:
// api/hono/src/middlewares/auth.ts
export const authMiddleware = async (c: Context, next: Next) => {
const session = await auth.api.getSession({
headers: c.req.raw.headers,
})
if (!session) {
return c.json({ error: "Unauthorized" }, 401)
}
c.set("session", session)
await next()
}Common Patterns
Role-Based Access Control
Extend Better Auth with custom roles:
// Add roles to your user schema
export const users = pgTable("users", {
// ...
role: text("role").notNull().default("user"),
})
// Check roles in middleware
if (session.user.role !== "admin") {
return c.json({ error: "Forbidden" }, 403)
}Multi-Tenancy Support
Better Auth can be extended for organization/team support, which is planned for ZeroStarter's future features.
Testing Authentication
Always test your authentication flows:
- Test login/logout flows
- Verify protected routes
- Test OAuth callbacks
- Validate session expiration
- Test error handling
Monitoring and Logging
Track authentication events:
- Failed login attempts
- Successful logins
- Session creation/destruction
- OAuth provider callbacks
Conclusion
Better Auth provides a solid foundation for authentication in SaaS applications. Combined with ZeroStarter's structure, you get:
- Secure authentication out of the box
- Type-safe API throughout
- Easy integration with multiple providers
- Scalable architecture for growth
By following these practices and leveraging Better Auth's features, you can build secure, user-friendly authentication that scales with your SaaS application.