Back to Skills

grey-haven-authentication-patterns

greyhaven-ai
Updated Yesterday
24 views
15
2
15
View on GitHub
Otherai

About

This skill provides Grey Haven's authentication patterns using better-auth for TanStack Start projects. It implements multi-tenant authentication with magic links, passkeys, OAuth providers, Redis session management, and JWT claims including tenant_id. Use this when implementing authentication features in multi-tenant applications.

Quick Install

Claude Code

Recommended
Plugin CommandRecommended
/plugin add https://github.com/greyhaven-ai/claude-code-config
Git CloneAlternative
git clone https://github.com/greyhaven-ai/claude-code-config.git ~/.claude/skills/grey-haven-authentication-patterns

Copy and paste this command in Claude Code to install this skill

Documentation

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:

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:

# 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

// 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

// Sign up with email verification
await auth.signUp.email({
  email: "[email protected]",
  password: "secure-password",
  name: "John Doe",
  data: {
    tenant_id: tenantId, // Include tenant context
  },
});

// Sign in
await auth.signIn.email({
  email: "[email protected]",
  password: "secure-password",
});

2. Magic Links

// Send magic link
await auth.magicLink.send({
  email: "[email protected]",
  callbackURL: "/auth/verify",
});

// Verify magic link token
await auth.magicLink.verify({
  token: tokenFromEmail,
});

3. OAuth Providers

// Google OAuth
export const auth = betterAuth({
  // ... other config
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
      scopes: ["email", "profile"],
    },
  },
});

// Redirect to Google
await auth.signIn.social({
  provider: "google",
  callbackURL: "/auth/callback",
});

4. Passkeys (WebAuthn)

// Enable passkeys
export const auth = betterAuth({
  // ... other config
  passkey: {
    enabled: true,
  },
});

// Register passkey
await auth.passkey.register({
  name: "My MacBook",
});

// Authenticate with passkey
await auth.passkey.authenticate();

Session Management

JWT Claims with tenant_id

// Middleware to extract tenant from JWT
export async function getTenantFromSession() {
  const session = await auth.api.getSession();
  
  if (!session) {
    throw new Error("Not authenticated");
  }

  return {
    userId: session.user.id,
    tenantId: session.user.tenant_id, // From JWT claims
    user: session.user,
  };
}

Session Storage with Redis

// Use Upstash Redis for sessions
export const auth = betterAuth({
  // ... other config
  session: {
    expiresIn: 60 * 60 * 24 * 7, // 7 days
    updateAge: 60 * 60 * 24, // Refresh daily
    cookieCache: {
      enabled: true,
      maxAge: 5 * 60, // 5 minutes
    },
  },
});

Protected Routes

TanStack Router beforeLoad

// routes/_authenticated/_layout.tsx
import { createFileRoute, redirect } from "@tanstack/react-router";
import { getTenantFromSession } from "~/lib/server/auth";

export const Route = createFileRoute("/_authenticated/_layout")({
  beforeLoad: async () => {
    try {
      const { userId, tenantId, user } = await getTenantFromSession();
      return { session: { userId, tenantId, user } };
    } catch {
      throw redirect({
        to: "/auth/login",
        search: { redirect: location.href },
      });
    }
  },
});

Supporting Documentation

All supporting files are under 500 lines per Anthropic best practices:

When to Apply This Skill

Use this skill when:

  • Implementing user authentication
  • Adding OAuth providers (Google, GitHub)
  • Setting up magic link authentication
  • Configuring passkey support
  • Managing user sessions
  • Implementing multi-tenant auth
  • Securing API endpoints
  • Setting up protected routes

Template Reference

These patterns are from Grey Haven's production templates:

  • cvi-template: TanStack Start + better-auth + multi-tenant

Critical Reminders

  1. tenant_id: Always include in users and sessions tables
  2. Doppler: Use for all auth secrets (never commit!)
  3. Email verification: Required for email/password signup
  4. JWT claims: Include tenant_id in session data
  5. Protected routes: Use beforeLoad for auth checks
  6. Redis sessions: Use Upstash for distributed sessions
  7. OAuth secrets: Store in Doppler (Google, GitHub, etc.)
  8. RLS policies: Create for users and sessions tables
  9. Session expiry: 7 days default, refresh daily
  10. Magic links: 15-minute expiry, single-use tokens

GitHub Repository

greyhaven-ai/claude-code-config
Path: grey-haven-plugins/security/skills/authentication-patterns

Related Skills

sglang

Meta

SGLang is a high-performance LLM serving framework that specializes in fast, structured generation for JSON, regex, and agentic workflows using its RadixAttention prefix caching. It delivers significantly faster inference, especially for tasks with repeated prefixes, making it ideal for complex, structured outputs and multi-turn conversations. Choose SGLang over alternatives like vLLM when you need constrained decoding or are building applications with extensive prefix sharing.

View skill

evaluating-llms-harness

Testing

This Claude Skill runs the lm-evaluation-harness to benchmark LLMs across 60+ standardized academic tasks like MMLU and GSM8K. It's designed for developers to compare model quality, track training progress, or report academic results. The tool supports various backends including HuggingFace and vLLM models.

View skill

llamaguard

Other

LlamaGuard is Meta's 7-8B parameter model for moderating LLM inputs and outputs across six safety categories like violence and hate speech. It offers 94-95% accuracy and can be deployed using vLLM, Hugging Face, or Amazon SageMaker. Use this skill to easily integrate content filtering and safety guardrails into your AI applications.

View skill

langchain

Meta

LangChain is a framework for building LLM applications using agents, chains, and RAG pipelines. It supports multiple LLM providers, offers 500+ integrations, and includes features like tool calling and memory management. Use it for rapid prototyping and deploying production systems like chatbots, autonomous agents, and question-answering services.

View skill