This project demonstrates the implementation of authentication in a SvelteKit application using the better-auth
library. It showcases various authentication flows including OAuth with GitHub and Email OTP (One-Time Password) authentication.
better-auth-sveltekit/
āāā src/
ā āāā lib/
ā ā āāā models/ # Data models
ā ā ā āāā user.ts # User interface definition
ā ā āāā server/
ā ā ā āāā auth.ts # Better-auth configuration
ā ā ā āāā email.ts # Email service using AWS SES
ā ā ā āāā db/ # Database connection and schemas
ā ā āāā auth-client.ts # Client-side auth utilities
ā āāā hooks.server.ts # SvelteKit hooks for auth middleware
ā āāā routes/
ā āāā auth/ # Authentication routes
ā ā āāā oauth/ # OAuth provider routes (GitHub)
ā ā āāā verify-otp/ # OTP verification
ā ā āāā sign-out/ # Sign out functionality
ā āāā +page.svelte # Protected home page
āāā drizzle.config.ts # Drizzle ORM configuration
This project implements OAuth authentication with GitHub, allowing users to sign in with their GitHub accounts. The flow works as follows:
The Email OTP flow provides a passwordless authentication method:
This project demonstrates how to integrate the better-auth
library with SvelteKit, including:
// src/lib/server/auth.ts
export const auth = betterAuth({
appName: 'BetterAuth SvelteKit Example',
advanced: {
cookiePrefix
},
emailAndPassword: {
enabled: false
},
socialProviders: {
github: {
clientId: OAUTH_GITHUB_CLIENT_ID,
clientSecret: OAUTH_GITHUB_CLIENT_SECRET
}
},
database: drizzleAdapter(db, {
provider: 'sqlite'
}),
plugins: [
sveltekitCookies(),
emailOTP({
async sendVerificationOTP({ email, otp, type }) {
// Email sending logic
}
})
]
});
// src/lib/auth-client.ts
export function createAuthClient(baseURL: string = page.url.origin) {
return createBetterAuthClient({
baseURL,
plugins: [emailOTPClient()]
});
}
// src/hooks.server.ts
const setupAuthHandler: Handle = ({ event, resolve }) => {
return svelteKitHandler({ event, resolve, auth });
};
const authGuard: Handle = async ({ event, resolve }) => {
const session = await auth.api.getSession({
headers: event.request.headers
});
// Route protection logic
// ...
};
export const handle: Handle = sequence(setupAuthHandler, authGuard);
This project uses Drizzle ORM with SQLite to store user data and sessions:
// src/lib/server/db/schemas/auth-schema.ts
export const user = sqliteTable('user', {
id: text('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull().unique(),
emailVerified: integer('email_verified', { mode: 'boolean' }).notNull(),
image: text('image'),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull()
});
export const session = sqliteTable('session', {
// Session schema
});
export const account = sqliteTable('account', {
// Account schema
});
export const verification = sqliteTable('verification', {
// Verification tokens schema
});
Create a .env
file with the following variables:
DATABASE_URL=file:./local.db
OAUTH_GITHUB_CLIENT_ID=your_github_client_id
OAUTH_GITHUB_CLIENT_SECRET=your_github_client_secret
AWS_ACCESS_KEY_ID=your_aws_access_key
AWS_SECRET_ACCESS_KEY=your_aws_secret_key
AWS_REGION=your_aws_region
# Install dependencies
npm install
# Create database schema
npm run db:push
# Start development server
npm run dev
The authentication guard in hooks.server.ts
protects routes by checking for an active session:
// Redirect to login if no session and not on login page
if (!session && !event.url.pathname.startsWith('/auth')) {
return redirect(302, '/auth');
}
// Redirect to home if session and on login page
if (session && event.url.pathname.startsWith('/auth')) {
// Check if it's not the sign-out route before redirecting
if (!event.url.pathname.includes('/auth/sign-out')) {
return redirect(302, '/');
}
}
The email OTP workflow is implemented with these main components:
Contributions are welcome! This project serves as an example implementation of better-auth with SvelteKit. Feel free to submit issues or pull requests.
MIT