Awesome-omni-skill api

Guidelines for the sveltekit-auth library architecture

install
source · Clone the upstream repo
git clone https://github.com/diegosouzapw/awesome-omni-skill
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/development/api" ~/.claude/skills/diegosouzapw-awesome-omni-skill-api-b7f63c && rm -rf "$T"
manifest: skills/development/api/SKILL.md
source content

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

npx sveltekit-auth init [options]

Options

OptionDescriptionDefault
-d, --database
postgres, mysql, sqlitepostgres
--orm
drizzle, prismadrizzle
-o, --output
Output directorysrc/lib/server/schemas
-t, --tables
Table casing: snake, camel, pascalsnake
-c, --columns
Column casing: snake, camel, pascalsnake
--id
ID type: uuid, cuiduuid
--singular
Use singular table names(plural)
--prefix
Table name prefix (e.g.,
auth_
)
(none)
--soft-delete
Add deletedAt columnfalse
--dry-run
Preview without writingfalse
-f, --force
Overwrite existing filesfalse

Generated Files

The CLI creates two files:

1.

users.ts
- User-owned, extendable

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

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

Examples

# 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

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:

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

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

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

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:

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

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

RouteMethodDescription
/auth/signin
GETSign-in page
/auth/signin/:provider
POSTInitiate OAuth flow
/auth/callback/:provider
GETOAuth callback
/auth/signout
POSTSign out
/auth/session
GETGet current session (JSON)
/auth/csrf
GETGet CSRF token

Session Strategies

JWT Strategy (default)

Sessions stored in signed cookies. No database calls for session validation.

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

Database Strategy

Sessions stored in database. Allows server-side session revocation.

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

Route Protection

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

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:

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:

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

SpecDescription
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