# API

> Guidelines for the sveltekit-auth library architecture

- Skill: `diegosouzapw/api-2` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add diegosouzapw/api-2`
- Raw SKILL.md: https://api.skillmd.com/api/skills/diegosouzapw/api-2/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: diegosouzapw (https://skillmd.com/u/diegosouzapw)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/diegosouzapw/api-2

---


# API Design Skill

Guidelines for designing and implementing the sveltekit-auth library.

## Library Architecture

This is an authentication library for SvelteKit applications. It provides:

- **CLI** - Schema generation with customizable options
- **Providers** - OAuth (GitHub, Google, Discord) and credentials authentication
- **Adapters** - Database abstraction following the Repository pattern
- **Middleware** - Route protection and session handling
- **Flows** - Password reset, email verification, etc.

```
src/
  cli/
    index.ts            # CLI for schema generation
  lib/
    providers/          # Authentication providers
      oauth.ts          # Base OAuth implementation
      github.ts         # GitHub provider
      google.ts         # Google provider
      discord.ts        # Discord provider
      credentials.ts    # Username/password provider
    adapters/           # Database adapters (Repository pattern)
      drizzle.ts        # Drizzle ORM adapter
      prisma.ts         # Prisma adapter (planned)
      memory.ts         # In-memory adapter (testing)
    middleware/         # SvelteKit middleware
      index.ts          # Main auth handle
      routes.ts         # Route protection helpers
    flows/              # Authentication flows
      verification.ts   # Email verification
      password-reset.ts # Password reset flow
    client/             # Client-side helpers
      auth-client.ts    # Browser auth client
      actions.ts        # Form action helpers
    utils/              # Utilities
      jwt.ts            # JWT handling
      session.ts        # Session management
      password.ts       # Password hashing
      crypto.ts         # Crypto utilities
    types.ts            # TypeScript interfaces
    index.ts            # Main exports
```

## CLI Schema Generation

The CLI generates schema files that users own and can extend. This enforces the base structure while allowing full customization.

### Usage

```bash
npx sveltekit-auth init [options]
```

### Options

| Option | Description | Default |
|--------|-------------|---------|
| `-d, --database` | postgres, mysql, sqlite | postgres |
| `--orm` | drizzle, prisma | drizzle |
| `-o, --output` | Output directory | src/lib/server/schemas |
| `-t, --tables` | Table casing: snake, camel, pascal | snake |
| `-c, --columns` | Column casing: snake, camel, pascal | snake |
| `--id` | ID type: uuid, cuid | uuid |
| `--singular` | Use singular table names | (plural) |
| `--prefix` | Table name prefix (e.g., `auth_`) | (none) |
| `--soft-delete` | Add deletedAt column | false |
| `--dry-run` | Preview without writing | false |
| `-f, --force` | Overwrite existing files | false |

### Generated Files

The CLI creates two files:

**1. `users.ts` - User-owned, extendable**
```typescript
// Generated by CLI - extend with your custom fields
export const users = pgTable('users', {
  id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
  name: text('name'),
  email: text('email'),
  image: text('image'),
  createdAt: timestamp('created_at').defaultNow().notNull(),
  updatedAt: timestamp('updated_at').defaultNow().notNull(),

  // Add your custom fields here:
  // role: text('role').$type<'user' | 'admin'>().default('user'),
  // organizationId: text('organization_id').references(() => organizations.id),
});
```

**2. `auth.ts` - Library-managed, don't modify**
```typescript
// Internal auth tables - typically don't modify
export const accounts = pgTable('accounts', { /* ... */ });
export const sessions = pgTable('sessions', { /* ... */ });
export const verifications = pgTable('verifications', { /* ... */ });
```

### Examples

```bash
# Default: PostgreSQL + Drizzle, snake_case, plural, UUID
npx sveltekit-auth init

# MySQL with camelCase columns
npx sveltekit-auth init -d mysql --columns camel

# Prisma with table prefix
npx sveltekit-auth init --orm prisma --prefix auth_

# Preview what will be generated
npx sveltekit-auth init --dry-run

# Use CUID for IDs with soft deletes
npx sveltekit-auth init --id cuid --soft-delete
```

## Adapter Pattern (Repository)

All database adapters implement the `Adapter` interface, which follows the Repository pattern. This provides a consistent API regardless of the underlying database or ORM.

### Why Repository Pattern?

1. **Consistent interface** - Same methods whether using Drizzle, Prisma, or custom adapter
2. **Swappable implementations** - Change database without changing application code
3. **Shared across routes** - Both API endpoints and form actions use the same adapter
4. **Testable** - Use createMemoryAdapter for unit tests

### Adapter Interface

```typescript
interface Adapter {
  // User methods - only requires 'id' field
  createUser(data: Record<string, unknown>): Promise<{ id: string; [key: string]: unknown }>;
  getUser(id: string): Promise<{ id: string; [key: string]: unknown } | null>;
  getUserByEmail(email: string): Promise<{ id: string; [key: string]: unknown } | null>;
  getUserByAccount(params: { provider: string; providerAccountId: string }): Promise<{ id: string; [key: string]: unknown } | null>;
  updateUser(user: { id: string; [key: string]: unknown }): Promise<{ id: string; [key: string]: unknown }>;
  deleteUser(id: string): Promise<void>;

  // Account methods
  linkAccount(account: Omit<AdapterAccount, 'id' | 'createdAt' | 'updatedAt'>): Promise<AdapterAccount>;
  unlinkAccount(params: { provider: string; providerAccountId: string }): Promise<void>;
  getAccount(params: { provider: string; providerAccountId: string }): Promise<AdapterAccount | null>;
  getAccountByLogin?(provider: string, login: string): Promise<AdapterAccount | null>;
  updateAccount?(accountId: string, data: Partial<AdapterAccount>): Promise<AdapterAccount | null>;

  // Session methods
  createSession(session: Omit<AdapterSession, 'id' | 'createdAt' | 'updatedAt'>): Promise<AdapterSession>;
  getSessionAndUser(sessionToken: string): Promise<{ session: AdapterSession; user: { id: string; [key: string]: unknown } } | null>;
  updateSession(session: { sessionToken: string; [key: string]: unknown }): Promise<AdapterSession | null>;
  deleteSession(sessionToken: string): Promise<void>;

  // Verification token methods
  createVerificationToken(token: VerificationToken): Promise<VerificationToken>;
  useVerificationToken(params: { identifier: string; token: string }): Promise<VerificationToken | null>;
}
```

### User Schema Flexibility

The library only requires `user.id` for relationships. Everything else flows through untouched:

```typescript
// Library internals only access user.id
const session = await adapter.createSession({
  userId: user.id,  // Only field we need
  sessionToken: generateToken(),
  expires: new Date(Date.now() + maxAge)
});

// User's custom fields pass through to their application
const user = await adapter.getUser(id);
// user.role, user.organizationId, etc. - all available
```

### Adapter Usage

**In API endpoints:**
```typescript
// src/routes/api/users/[id]/+server.ts
import { json } from '@sveltejs/kit';

export const GET: RequestHandler = async ({ params, locals }) => {
  const user = await locals.auth.adapter.getUser(params.id);
  if (!user) return json({ error: 'Not found' }, { status: 404 });
  return json(user);
};
```

**In form actions:**
```typescript
// src/routes/settings/+page.server.ts
export const actions: Actions = {
  updateProfile: async ({ request, locals }) => {
    const data = await request.formData();
    const user = await locals.auth.adapter.updateUser({
      id: locals.user.id,
      name: data.get('name'),
      // Custom fields work too
      bio: data.get('bio')
    });
    return { success: true, user };
  }
};
```

**In tests:**
```typescript
import { createMemoryAdapter } from '@sveltekit-auth/core/adapters';

const adapter = createMemoryAdapter();
const user = await adapter.createUser({ email: 'test@example.com' });
```

## Provider Pattern

Providers implement authentication strategies:

```typescript
// OAuth Provider
export function GitHub(config: {
  clientId: string;
  clientSecret: string;
}): OAuthProviderConfig {
  return {
    id: 'github',
    name: 'GitHub',
    type: 'oauth',
    authorization: 'https://github.com/login/oauth/authorize',
    token: 'https://github.com/login/oauth/access_token',
    userinfo: 'https://api.github.com/user',
    profile(profile) {
      return {
        id: profile.id.toString(),
        name: profile.name ?? profile.login,
        email: profile.email,
        image: profile.avatar_url
      };
    },
    ...config
  };
}

// Credentials Provider
export function Credentials(config: {
  loginType: 'email' | 'username' | 'either';
  authorize: (credentials, request) => Promise<User | null>;
}): CredentialsProviderConfig {
  return {
    id: 'credentials',
    name: 'Credentials',
    type: 'credentials',
    ...config
  };
}
```

## Middleware Integration

The auth middleware integrates with SvelteKit's handle hook:

```typescript
// src/hooks.server.ts
import { createAuth } from '@sveltekit-auth/core';
import { createDrizzleAdapter } from '@sveltekit-auth/core/adapters/drizzle';
import GitHub from '@sveltekit-auth/core/providers/github';
import { db } from '$lib/server/db';
import * as schema from '$lib/server/schemas/auth';

export const handle = createAuth({
  adapter: createDrizzleAdapter(db, schema),
  providers: [
    GitHub({
      clientId: env.GITHUB_CLIENT_ID,
      clientSecret: env.GITHUB_CLIENT_SECRET
    })
  ],
  secret: env.AUTH_SECRET
});
```

## Auth Routes

The library handles these routes under the configured base path (default: `/auth`):

| Route | Method | Description |
|-------|--------|-------------|
| `/auth/signin` | GET | Sign-in page |
| `/auth/signin/:provider` | POST | Initiate OAuth flow |
| `/auth/callback/:provider` | GET | OAuth callback |
| `/auth/signout` | POST | Sign out |
| `/auth/session` | GET | Get current session (JSON) |
| `/auth/csrf` | GET | Get CSRF token |

## Session Strategies

### JWT Strategy (default)
Sessions stored in signed cookies. No database calls for session validation.

```typescript
{ session: { strategy: 'jwt', maxAge: 30 * 24 * 60 * 60 } }
```

### Database Strategy
Sessions stored in database. Allows server-side session revocation.

```typescript
{ session: { strategy: 'database', maxAge: 30 * 24 * 60 * 60 } }
```

## Route Protection

```typescript
// src/routes/dashboard/+page.server.ts
import { redirect } from '@sveltejs/kit';

export async function load({ locals }) {
  const session = await locals.auth.getSession();
  if (!session) {
    throw redirect(302, '/auth/signin');
  }
  return { user: session.user };
}
```

## Creating New Adapters

To create a new adapter (e.g., for a different database), implement the `Adapter` interface:

```typescript
import type { Adapter } from '@sveltekit-auth/core';

export function MyCustomAdapter(db: MyDB): Adapter {
  return {
    async createUser(data) {
      const user = await db.users.insert(data);
      return user;
    },

    async getUser(id) {
      return db.users.findById(id);
    },

    // ... implement all required methods
  };
}
```

The adapter must:
1. Implement all required methods from the `Adapter` interface
2. Work with the schema generated by the CLI (or compatible schema)
3. Return objects with at least an `id` field for users
4. Handle the relationship between users, accounts, and sessions

## Error Handling

Adapters throw `AdapterError` for known error conditions:

```typescript
import { AdapterError, AdapterErrorCodes } from '@sveltekit-auth/core';

class AdapterError extends Error {
  code: string;
}

const AdapterErrorCodes = {
  USER_NOT_FOUND: 'USER_NOT_FOUND',
  USER_ALREADY_EXISTS: 'USER_ALREADY_EXISTS',
  ACCOUNT_NOT_FOUND: 'ACCOUNT_NOT_FOUND',
  ACCOUNT_ALREADY_LINKED: 'ACCOUNT_ALREADY_LINKED',
  SESSION_NOT_FOUND: 'SESSION_NOT_FOUND',
  SESSION_EXPIRED: 'SESSION_EXPIRED',
  TOKEN_NOT_FOUND: 'TOKEN_NOT_FOUND',
  TOKEN_EXPIRED: 'TOKEN_EXPIRED',
  DATABASE_ERROR: 'DATABASE_ERROR'
};
```

## Middleware Utilities

The library exports additional middleware utilities:

```typescript
import { createAuth, createProtectedRoutesMiddleware, sequence } from '@sveltekit-auth/core';

// Combine multiple middleware handlers
export const handle = sequence(
  createAuth({ /* config */ }),
  createProtectedRoutesMiddleware({
    protectedRoutes: ['/dashboard/*', '/settings/*'],
    publicRoutes: ['/auth/*', '/about'],
    unauthorizedRedirect: '/auth/signin'
  })
);
```

## Roadmap & TODOs

See `.claude/todos/improvements.todo.md` for planned features:

**High Priority:**
- Account linking for OAuth (link multiple providers to one account)
- More OAuth providers (Apple, Microsoft, Twitter, Facebook, LinkedIn)
- Rate limiting for auth endpoints

**Medium Priority:**
- Magic link authentication (passwordless)
- Two-factor authentication (TOTP)
- Session management utilities

**Lower Priority:**
- Full CSRF protection
- Audit logging

## Detailed Specifications

For comprehensive details, see the spec files in `.claude/specs/`:

| Spec | Description |
|------|-------------|
| `architecture.spec.md` | System architecture, data flow, security overview |
| `adapters.spec.md` | Database adapter interface, schema details |
| `cli.spec.md` | CLI options, naming conventions, output formats |
| `providers.spec.md` | OAuth and credentials provider configuration |
| `flows.spec.md` | Email verification, password reset flows |
| `security.spec.md` | Password hashing, session encryption, CSRF protection |

