Grey Haven's authentication patterns using better-auth - magic links, passkeys, OAuth providers, session management with Redis, JWT claims with tenant_id, and Doppler for auth secrets. Use when implementing authentication features.
View on GitHubgreyhaven-ai/claude-code-config
security
grey-haven-plugins/security/skills/authentication-patterns/SKILL.md
January 21, 2026
Select agents to install to:
npx add-skill https://github.com/greyhaven-ai/claude-code-config/blob/main/grey-haven-plugins/security/skills/authentication-patterns/SKILL.md -a claude-code --skill grey-haven-authentication-patternsInstallation paths:
.claude/skills/grey-haven-authentication-patterns/# Grey Haven Authentication Patterns
Follow Grey Haven Studio's authentication patterns using better-auth for TanStack Start projects with multi-tenant support.
## Stack
- **better-auth**: Authentication library for TanStack Start
- **Drizzle ORM**: Database adapter for better-auth
- **Doppler**: Secret management (BETTER_AUTH_SECRET, OAuth keys)
- **Redis**: Session storage (via Upstash)
- **PostgreSQL**: User and session data with RLS
## Critical Requirements
### Multi-Tenant Authentication
**ALWAYS include tenant_id in auth tables**:
```typescript
export const users = pgTable("users", {
id: uuid("id").primaryKey().defaultRandom(),
tenant_id: uuid("tenant_id").notNull(), // CRITICAL!
email_address: text("email_address").notNull().unique(),
// ... other fields
});
export const sessions = pgTable("sessions", {
id: uuid("id").primaryKey().defaultRandom(),
user_id: uuid("user_id").references(() => users.id),
tenant_id: uuid("tenant_id").notNull(), // CRITICAL!
// ... other fields
});
```
### Doppler for Secrets
**NEVER commit auth secrets**:
```bash
# Doppler provides these at runtime
BETTER_AUTH_SECRET=<generated-secret>
BETTER_AUTH_URL=https://app.example.com
GOOGLE_CLIENT_ID=<from-google-console>
GOOGLE_CLIENT_SECRET=<from-google-console>
```
## Basic Configuration
```typescript
// lib/server/auth.ts
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "@better-auth/drizzle";
import { db } from "~/lib/server/db";
export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
schema,
}),
emailAndPassword: {
enabled: true,
requireEmailVerification: true,
},
secret: process.env.BETTER_AUTH_SECRET!,
baseURL: process.env.BETTER_AUTH_URL!,
trustedOrigins: [process.env.BETTER_AUTH_URL!],
});
```
## Authentication Methods
### 1. Email & Password
```typescript
// Sign up with email verification
await auth.signUp.email({
email: "user@example.com",
password: "secure-password",
Issues Found: