Ory Kratos for Next.js: Open-Source Auth with Email Verification and 2FA
Identity and authentication form the foundation of modern web applications, controlling access to sensitive features and protecting user data. Building robust, secure authentication systems from scratch presents numerous security pitfalls and edge cases. While managed solutions like Auth0 and Okta offer convenience, they introduce vendor lock-in, limited customization, and opaque ecosystems.
Ory Kratos provides an alternative: a feature-rich, enterprise-grade identity server that's fully open-source, offering complete control over data, user interfaces, and authentication logic. This guide explores Ory Kratos's architecture and demonstrates building a complete authentication system for Next.js applications, covering user registration, login, email verification, and two-factor authentication using the open-source Ory stack.
Understanding Ory Kratos
Ory Kratos is a backend-only, API-first identity management server designed to handle common identity-related tasks securely and efficiently.
Headless architecture philosophy
The term "headless" defines Kratos's core approach. Kratos doesn't include pre-built user interfaces like login forms or registration pages. Instead, it exposes comprehensive REST APIs that your application communicates with. This "Bring Your Own UI" (BYOUI) approach provides ultimate freedom to build user interfaces using any technology—React, Vue, Svelte, Next.js, or native mobile apps—styled to match your brand without constraints from third-party templates.
Core feature set
Self-service login and registration: Kratos handles common user flows including registration, login, and logout. It supports various login methods: username/password combinations, passwordless flows, and social logins via OpenID Connect.
Multifactor authentication (MFA/2FA): Enhance security with proven MFA methods like Time-based One-Time Passwords (TOTP) working with authenticator apps like Google Authenticator, and standards like FIDO2 and WebAuthn for hardware keys.
User management: Provides administrative APIs to create, read, update, and delete user identities and associated data.
Custom identity models: You control data associated with user identities. Using JSON schema, you can define custom fields like names, addresses, profile pictures, or any application-specific data.
Social logins: Simplify user experience by allowing sign-up and login using existing accounts from providers like Google, GitHub, Apple, and any OpenID Connect (OIDC) compliant provider.
Account verification and recovery: Kratos manages essential flows for verifying user identity (via email link or code) and account recovery using methods like "Forgot Password" flows and security codes.
Security and compliance
Security is a core design principle in Ory Kratos. The platform applies industry-standard security practices established by leading experts and organizations like the National Institute of Standards and Technology (NIST) and the Internet Engineering Task Force (IETF). It's designed for GDPR compliance, simplifying user data privacy management. One notable feature checks passwords against known data breaches, preventing users from choosing compromised credentials.
Modular ecosystem integration
Ory Kratos is one component of the larger Ory open-source ecosystem. While Kratos handles identity management, other Ory projects integrate seamlessly:
Ory Hydra: A certified OAuth 2.0 and OpenID Connect server.
Ory Keto: A global, scalable authorization server for managing complex user permissions.
Ory Polis: An enterprise-level SSO bridge.
Ory Oathkeeper: An identity and access proxy.
This modularity allows selecting components you need, creating bespoke solutions tailored to project requirements without unnecessary bloat.
Environment setup
The development environment uses Docker to run Kratos and its dependencies in isolated containers. The complete project code is available in this GitHub repository.
Project structure
Create the necessary directory structure to keep Kratos configuration separate from Next.js frontend code:
Create the configuration files:
The resulting project structure:
Docker and Kratos configuration
Docker Compose service definition
The docker-compose.yml file defines the multi-container application blueprint. It specifies which services to run, how they connect, and their configurations.
Service breakdown:
kratos-migrate: A one-off job running at service startup that applies necessary database migrations to users.db, creating tables Kratos needs for identity data storage.
kratos: The main Ory Kratos server exposing a public API on port 4433 (for frontend interactions) and an admin API on port 4434.
kratos-selfservice-ui-node: A reference UI provided by Ory, part of the standard quickstart setup but not used directly in this implementation.
mailslurper: A local fake SMTP server. When Kratos sends emails (like account verification), MailSlurper captures them, allowing viewing in a web interface without requiring a real email provider during development.
Identity schema definition
The identity.schema.json file defines user information structure using JSON Schema standard to describe user traits:
This schema defines user traits consisting of a required email and optional name object with first and last name properties. The schema instructs Kratos to use email as the primary identifier for password credentials and for verification/recovery flows.
Kratos server configuration
The kratos.yml file is the main Kratos server configuration, controlling everything from database connections to self-service flow URLs:
Key configuration points:
dsn: Points to the SQLite database file, mounted into the container.
serve.public.cors: Critical setting whitelisting the Next.js application's URL (http://localhost:3000), allowing browser requests to the Kratos API from a different origin.
selfservice.flows.*.ui_url: URLs telling Kratos where to redirect the user's browser at different authentication stages. For example, when a login flow initiates, Kratos redirects to http://127.0.0.1:3000/login, where the Next.js app renders the login form.
identity.schemas: Points to the identity.schema.json file.
courier.smtp: Configures Kratos to send emails through the local mailslurper service.
Next.js frontend implementation
Project initialization
Create the Next.js application in the root kratos-demo directory:
Navigate into the directory and install Ory dependencies:
Configuration files
Create environment variables in .env:
Create Ory configuration file mapping UI components to app paths:
Create Next.js middleware for automatic session management:
Authentication flow pages
Create pages in the Next.js app corresponding to ui_url paths defined in kratos.yml. Inside the app directory, create folders for login, register, settings, verification, recovery, and logout. Inside each folder, create a page.tsx file.
The code for most pages is nearly identical using Ory Elements. Here's the login page example:
Similar files for other flows replace getLoginFlow and <Login /> with appropriate counterparts (such as getRegistrationFlow and <Registration />). This pattern abstracts complexity of rendering forms, handling user input, and displaying errors.
Testing the authentication flow
Launching services
Start Docker services from the kratos-demo/docker directory:
This builds and starts all services defined in docker-compose.yml. Logs should indicate database migrations have run and the Kratos server is running.
Start the Next.js application in a separate terminal from kratos-demo/kratos-auth:
This starts the frontend application on http://localhost:3000.
User authentication journey
Registration: Navigate to http://localhost:3000 and click "Create Account". When attempting to sign up with a weak password like password123, Ory Kratos detects the password in data breaches and prevents its use.
Enter details with a strong password and click "Sign up".
Email verification: After registration, you're directed to verify your account. Navigate to the MailSlurper UI at http://localhost:4436 to see the verification email sent by Kratos.
Click the email to see the verification code, copy it, return to your app, paste the code into the verification form, and click "Continue". Your account is now verified.
Login and session management: Click "Sign In", enter your credentials, and sign in. The page displays a "Welcome Back" message and a JSON object containing current session information, proving Kratos successfully created a session.
Two-factor authentication (2FA): Click "Settings" to access the profile settings dashboard. Scroll to the "Authenticator App" section.
Open an authenticator app (like Google Authenticator) on your phone, scan the QR code, enter the 6-digit code into the "Verify code" field, and save. You've now enabled 2FA.
After logging out and attempting to log in again, you'll be prompted for the second factor authentication code from your app after entering your password.
Final thoughts
This guide covers fundamental capabilities. The Ory ecosystem offers deeper features including seamless integration with different databases, social logins, and migration guides from platforms like Auth0. The official Ory Kratos documentation provides comprehensive resources for exploring advanced features and leveraging this open-source tool in production applications.
The modular architecture allows starting with basic authentication and progressively adding capabilities like OAuth 2.0 (via Ory Hydra) or complex authorization rules (via Ory Keto) as requirements evolve.