Skip to content
Back to skills

Api

ASecurity

Guidelines for the sveltekit-auth library architecture

  • 57 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 31, 2026
databasestypescriptgobashsqltestinggitapidatabasesecurity

Works with

  • cli
  • api

Security analysis

A100/100

Scanned May 31, 2026

npx -y skills add diegosouzapw/awesome-omni-skill --skill api --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Api?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Api
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/diegosouzapw-api/badge)](https://www.skillsdirectory.com/skills/diegosouzapw-api)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: api
description: Guidelines for the sveltekit-auth library architecture
triggers:
  - api
  - auth
  - providers
  - adapters
  - middleware
  - oauth
  - credentials
  - session
  - cli
  - schema
files:
  - src/lib/index.ts
  - src/lib/types.ts
  - src/lib/adapters/drizzle.ts
  - src/lib/providers/oauth.ts
  - src/lib/middleware/index.ts
  - src/cli/index.ts
---

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

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.