Ktor Tutorial #14: Rate Limiting, CORS, and Security Headers

Your API has authentication, but that is only one layer of security. Without rate limiting, attackers can brute-force passwords. Without CORS, any website can call your API. Without security headers, your application is vulnerable to clickjacking and XSS attacks. In this tutorial, you will add three essential security features: CORS configuration, rate limiting, and security headers. These are requirements for any production API. Why These Security Features Matter CORS → Controls which websites can call your API Rate Limiting → Prevents brute-force attacks and abuse Security Headers → Prevents clickjacking, XSS, and MIME sniffing Dependencies Add the Ktor security plugins: ...

June 8, 2026 · 5 min

Ktor Tutorial #13: OAuth 2.0 — Sign In with Google

Your API has registration and login with email and password. But many users prefer to sign in with their Google account. It is faster and they do not need to remember another password. In this tutorial, you will add Google Sign-In using OAuth 2.0. You will learn how the OAuth flow works, how to handle the callback, and how to link OAuth accounts with existing email accounts. How OAuth 2.0 Works OAuth 2.0 is a protocol that lets users sign in with a third-party provider (Google, GitHub, etc.) without sharing their password with your application. ...

June 7, 2026 · 6 min

Ktor Tutorial #12: Registration and Login Flow

In the previous tutorial, you added JWT authentication. Users can register, login, and access protected routes. But the implementation was basic. There were no refresh tokens, no password validation, and no logout. In this tutorial, you will build a complete authentication flow. You will add refresh tokens with rotation, strong password validation, email validation, and a logout endpoint that revokes tokens. What We Will Build Here is the complete auth flow: ...

June 7, 2026 · 9 min

Ktor Tutorial #11: JWT Authentication — Securing Your API

Your API works. It has routes, a database, file uploads, and migrations. But anyone can access any endpoint. There is no authentication. In this tutorial, you will add JWT (JSON Web Token) authentication. Users will register, login, get a token, and use that token to access protected routes. How JWT Authentication Works JWT authentication follows this flow: 1. Client sends email + password → POST /api/auth/login 2. Server verifies credentials 3. Server generates a JWT token 4. Server sends token to client 5. Client stores token 6. Client sends token with every request → Authorization: Bearer <token> 7. Server verifies token and processes request The token contains encoded information (claims) about the user. The server can verify the token without a database query. ...

June 7, 2026 · 9 min

Ktor Tutorial #10: Database Migrations with Flyway

In the previous tutorials, we used SchemaUtils.create() to create database tables. This works for development, but it has a big problem: it cannot handle schema changes. What happens when you need to add a column? Rename a table? Change a data type? You cannot just drop the database and recreate it — production data would be lost. This is where database migrations come in. Why Migrations Matter Without migrations, you have these problems: ...

June 6, 2026 · 6 min

Ktor Tutorial #9: File Uploads and Static Files

Most APIs need to handle files. Profile pictures, document uploads, image galleries — file handling is a common requirement. In this tutorial, you will learn how to serve static files, handle file uploads via multipart form data, validate uploads, and protect against common security issues. Serving Static Files Ktor can serve static files from your resources directory or from the filesystem. From Resources Put files in src/main/resources/static/: src/main/resources/static/ ├── index.html ├── style.css └── logo.png Then configure the route: ...

June 6, 2026 · 7 min

Ktor Tutorial #8: Relationships and Advanced Queries

A real application has connected data. Users own notes. Notes have tags. Orders belong to customers. These connections are called relationships. In this tutorial, you will add relationships between tables, write JOIN queries, and build advanced filtering, sorting, and pagination. Types of Relationships Type Example Implementation One-to-Many One user has many notes Foreign key on notes table Many-to-Many Notes have many tags, tags belong to many notes Join table (note_tags) One-to-One One user has one profile Foreign key with unique constraint One-to-Many: Users → Notes A user can have many notes. Each note belongs to one user (or no user). ...

June 6, 2026 · 7 min

Ktor Tutorial #7: CRUD Operations — Building a REST API

We have a database. We have JSON serialization. Now it is time to build a real REST API. In this tutorial, you will build full CRUD (Create, Read, Update, Delete) operations for notes and users. You will learn the repository pattern, proper HTTP status codes, validation, and how to organize a production-ready API. The Repository Pattern In the previous tutorial, we put database queries directly in route handlers. This works for small projects but becomes messy as your API grows. ...

June 5, 2026 · 8 min

Ktor Tutorial #6: Database Setup — Exposed ORM with H2

Our API works, but the data lives in memory. Restart the server and everything is gone. Time to add a real database. In this tutorial, you will connect your Ktor API to a database using Exposed — JetBrains’ SQL library for Kotlin. We will use H2 for development and explain how to switch to PostgreSQL for production. What is Exposed? Exposed is a SQL library made by JetBrains. It gives you two ways to work with databases: ...

June 5, 2026 · 7 min

Ktor Tutorial #5: Serialization — JSON with kotlinx.serialization

In the previous tutorial, we built routes that return plain text. But real APIs use JSON. Clients send JSON requests and expect JSON responses. In this tutorial, you will add JSON serialization to your Ktor API using kotlinx.serialization — the official Kotlin serialization library. What is Content Negotiation? When a client sends a request, it tells the server what format it wants using the Accept header. When it sends data, it uses the Content-Type header. ...

June 5, 2026 · 8 min