Guidelines for the sveltekit-auth library architecture
Scanned 5/31/2026
Install via CLI
openskills install diegosouzapw/awesome-omni-skill---
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 |
No comments yet. Be the first to comment!