
Better Auth
Wire Better Auth into your app with PostgreSQL, session secrets, OAuth providers, SMTP, and optional Redis session storage.
Install
npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill better-authWhat is this skill?
- Environment template for DATABASE_URL, BETTER_AUTH_SECRET, and BETTER_AUTH_URL
- OAuth client placeholders for GitHub, Google, Microsoft, Facebook, Discord, LinkedIn, and Apple Sign In
- SMTP variables for magic links and email verification flows
- Redis-oriented session storage configuration hints in the kit
- Frontend NEXT_PUBLIC_BETTER_AUTH_URL alignment for split or monolithic apps
Adoption & trust: 998 installs on skills.sh; 271 GitHub stars; 3/3 security scanners passed (skills.sh audits).
Recommended Skills
Entra App Registrationmicrosoft/azure-skills
Azure Aigatewaymicrosoft/azure-skills
Lark Openapi Explorerlarksuite/cli
Supabasesupabase/agent-skills
Firebase Auth Basicsfirebase/agent-skills
Firebase Data Connectfirebase/agent-skills
Journey fit
Primary fit
Authentication and OAuth env configuration are integration work done while building the product backend. Better Auth touches external IdPs, email, and DB URLs—classic third-party integration setup, not validate or launch SEO.
Common Questions / FAQ
Is Better Auth safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Better Auth
# Database DATABASE_URL=postgresql://user:password@localhost:5432/dbname # Better Auth BETTER_AUTH_SECRET=your-secret-key-min-32-chars-generate-with-openssl-rand-base64-32 BETTER_AUTH_URL=http://localhost:3000 # Frontend URL (if separate from backend) NEXT_PUBLIC_BETTER_AUTH_URL=http://localhost:3000 # GitHub OAuth AUTH_GITHUB_CLIENT_ID=your_github_client_id AUTH_GITHUB_CLIENT_SECRET=your_github_client_secret # Google OAuth AUTH_GOOGLE_CLIENT_ID=your_google_client_id AUTH_GOOGLE_CLIENT_SECRET=your_google_client_secret # Microsoft OAuth AUTH_MICROSOFT_CLIENT_ID=your_microsoft_client_id AUTH_MICROSOFT_CLIENT_SECRET=your_microsoft_client_secret AUTH_MICROSOFT_TENANT_ID=common # Facebook OAuth AUTH_FACEBOOK_CLIENT_ID=your_facebook_client_id AUTH_FACEBOOK_CLIENT_SECRET=your_facebook_client_secret # Discord OAuth AUTH_DISCORD_CLIENT_ID=your_discord_client_id AUTH_DISCORD_CLIENT_SECRET=your_discord_client_secret # LinkedIn OAuth AUTH_LINKEDIN_CLIENT_ID=your_linkedin_client_id AUTH_LINKEDIN_CLIENT_SECRET=your_linkedin_client_secret # Apple Sign In AUTH_APPLE_CLIENT_ID=your_apple_client_id AUTH_APPLE_CLIENT_SECRET=your_apple_client_secret AUTH_APPLE_KEY_ID=your_apple_key_id AUTH_APPLE_TEAM_ID=your_apple_team_id # Email Configuration (for magic links and verification) SMTP_HOST=smtp.example.com SMTP_PORT=587 SMTP_SECURE=false SMTP_USER=your-smtp-user SMTP_PASSWORD=your-smtp-password SMTP_FROM=noreply@example.com SMTP_FROM_NAME=Your App Name # Redis (for session storage in production) REDIS_URL=redis://localhost:6379 # Session Configuration SESSION_EXPIRY=604800 # 7 days in seconds # 2FA Configuration TWO_FACTOR_ISSUER=YourApp # Organization Configuration ORGANIZATION_ENABLED=true # Rate Limiting RATE_LIMIT_MAX=100 RATE_LIMIT_WINDOW=900000 # 15 minutes in ms import { Controller, Post, Body, Get, Req, UseGuards, HttpCode, HttpStatus, } from '@nestjs/common'; import { AuthService } from './auth.service'; import { AuthGuard } from './auth.guard'; @Controller('auth') export class AuthController { constructor(private authService: AuthService) {} @Get('session') @HttpCode(HttpStatus.OK) async getSession(@Req() req) { const token = req.headers.authorization?.replace('Bearer ', ''); return this.authService.getSession(token); } @Post('sign-out') @UseGuards(AuthGuard) @HttpCode(HttpStatus.OK) async signOut(@Req() req) { // Requires authentication to prevent session enumeration attacks return this.authService.revokeSession(req.session.sessionToken); } @Get('sessions') @UseGuards(AuthGuard) async getSessions(@Req() req) { return this.authService.getUserSessions(req.user.id); } @Post('sessions/revoke-all') @UseGuards(AuthGuard) @HttpCode(HttpStatus.OK) async revokeAll(@Req() req) { return this.authService.revokeAllSessions(req.user.id); } @Post('verify-email') @HttpCode(HttpStatus.OK) async sendVerificationEmail(@Body() body: { email: string }) { return this.authService.sendVerificationEmail(body.email); } @Post('reset-password') @HttpCode(HttpStatus.OK) async resetPassword( @Body() body: { token: string; newPassword: string } ) { // IMPORTANT: Token must be a cryptographically secure random string // sent to the user's email address via a forgot-password flow return this.authService.resetPassword(body.token, body.newPassword); } } import { Injectable, CanActivate, ExecutionContext, UnauthorizedException, } from '@nestjs/common'; import { auth } from './auth.instance'; @Injectable() export class AuthGuard implements CanActivate { async canActivate(context: ExecutionContext): Promise<boolean> { const request = context.switchToHttp().getRequest(); const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) { throw new UnauthorizedException('No token provided'); } const session = await auth.api.getSession({ headers: new Headers({ authorizati