# Command Reference (/docs/command-reference) ## Overview Here is a reference for the most common commands used in this project, all run from the project root. ## Development ```bash # Start all development servers + Drizzle Studio pnpm dev # Start only the application development servers pnpm dev:app ``` ## Code Quality ```bash # Run linting across all packages pnpm lint # Auto-fix linting and formatting issues pnpm lint:fix # Run TypeScript type checking across all packages pnpm typecheck ``` ## Database ```bash # Generate auth schema from Better Auth config pnpm db:schema # Generate a new SQL migration from schema changes pnpm db:generate # Apply all pending migrations to the database pnpm db:migrate # Open the Drizzle Studio GUI in your browser pnpm db:studio # Run the complete setup: schema -> generate -> migrate pnpm db:setup ``` ## Build ```bash # Build all apps and packages for production pnpm build ``` # Welcome to Starter Kit (/docs) ## Introduction This project is a comprehensive, full-stack monorepo designed to provide a robust foundation for building modern applications with a focus on type-safety, scalability, and developer experience. ## Who is this for? This starter kit is for developers who want to: * Quickly bootstrap a new project with a solid, production-ready architecture. * Learn best practices for building applications with TypeScript, Hono, Drizzle ORM, and other modern tools. * Understand how to structure and manage a complex project using a monorepo. ## Core Philosophy This project is built on a set of core principles. These principles guide our architectural decisions for the codebase: * **Type Safety**: Code must be type-safe at compile time and runtime. * **Schema as Code**: Database schemas are version-controlled and generated from code. * **Separation of Concerns**: A clear boundary between applications (`apps`) and shared libraries (`packages`). * **Documentation as Code**: APIs and workflows are documented as part of the development process. ## For AI and LLMs This documentation is also available in formats optimized for AI consumption: * **Full Documentation**: A single [llms-full.txt](/llms-full.txt) file containing the entire documentation in plain text. * **Per-Page MDX**: Per-page LLM MDX by appending `.mdx` to docs URLs (e.g., `/docs/auth` → `/docs/auth.mdx`). * **Copy Markdown**: Each page also has a "Copy Markdown" button that provides plain text ready for LLMs. # Quick Start (/docs/installation) ## Overview This guide will walk you through the process of setting up the starter kit on your local machine. ## Prerequisites * [Node.js](https://nodejs.org/en/) (v18 or higher) * [pnpm](https://pnpm.io/installation) (v9.0.0 or higher) * [Docker](https://www.docker.com/get-started) (for running the PostgreSQL database) ## 1. Installation First, clone the repository and install the dependencies using `pnpm`: ```bash git clone https://github.com/yurisasc/starter-kit.git cd starter-kit pnpm install ``` ## 2. Environment Setup The project uses `.env` files for managing environment variables. Instead of manually creating each file, you can use our automated setup script: ```bash pnpm setup:env ``` This script will: * Copy all `.env.example` files to their respective `.env` files * Generate a secure secret for the auth server automatically * Skip any files that already exist to avoid overwriting your customizations **Manual Setup (Alternative)** If you prefer to set up manually, you can copy the example files: ```bash # Copy example files cp apps/auth/.env.example apps/auth/.env cp apps/api/.env.example apps/api/.env cp apps/mcp/.env.example apps/mcp/.env cp packages/database/.env.example packages/database/.env # Generate auth secret openssl rand -base64 32 ``` Then replace `your-secret-key-minimum-32-characters-long-change-this-in-production` in `apps/auth/.env` with the generated secret. ## 3. Start the Database The project uses a PostgreSQL database, which can be easily started with Docker: ```bash docker run -d \ --name auth-postgres \ -e POSTGRES_PASSWORD=password \ -e POSTGRES_DB=auth_db \ -p 5432:5432 \ postgres:18 ``` ## 4. Run Database Setup With the database running, you can now set up the schema and run the initial migrations: ```bash pnpm db:setup ``` This command will: 1. Generate the Drizzle schema from the `better-auth` configuration. 2. Create the SQL migration files. 3. Apply the migrations to your database. ## 5. Start the Development Servers Finally, start all the development servers with a single command: ```bash pnpm dev ``` This will start: * The **Auth server** at `http://localhost:3001` * The **API server** at `http://localhost:3010` * The **Documentation site** at `http://localhost:3000` * **Drizzle Studio** at `https://local.drizzle.studio` # Future Project Structure (/docs/future-structure) ## Overview This starter kit provides a solid foundation, but it is designed to be extended. Here are some ways the project structure might evolve. ## Adding a Web Frontend A common next step is to add a web application (e.g., a Next.js or Remix app) that consumes the `api` server. * **Location**: A new directory would be created at `apps/web`. * **Authentication**: The web app would interact with the `auth` server to handle user sign-in and session management. * **API Consumption**: It would make authenticated requests to the `api` server by first requesting a JWT from the `auth` server, as outlined in the authentication architecture. ## Adding a Mobile App The architecture is already designed to support a mobile client. * **Location**: A new directory could be created at `apps/mobile` for an Expo or React Native project. * **Authentication**: The mobile app would use a token-based flow, storing session tokens securely and requesting JWTs for API calls. ## Adding More Shared Packages As the project grows, you might extract more shared logic into the `packages/` directory. * **Example**: A `@repo/ui` package could be created to share React components between the `docs` site and a new `web` application. * **Example**: A `@repo/utils` package could house common utility functions used by multiple backend services. # Troubleshooting (/docs/troubleshooting) ## Overview This guide covers common issues you may encounter while setting up or running the project. ### Invalid Environment Variables * **Error**: `Invalid environment variables` on startup. * **Solution**: Make sure you have a `.env` file in each requiring project, and that all required variables are set. See [Quick Start](/docs/installation) for more information. ### Database Connection Failure * **Error**: `Cannot connect to database` or `ECONNREFUSED`. * **Solution**: Make sure your PostgreSQL Docker container is running (`docker ps`). If not, start it with `docker start auth-postgres`. ### Port Conflicts * **Error**: `Port 3001 already in use`. * **Solution**: Another process is using the required port. Find and stop it (`lsof -i :3001`), or change the `PORT` in the appropriate `.env` file. ### Migration Errors * **Error**: `Migration failed` or `relation already exists`. * **Solution**: For development, the easiest fix is often to reset the database by dropping and recreating it in Docker, then re-running `pnpm db:migrate`. # Code & Commit Quality (/docs/code-quality) ## Overview This project enforces a high standard of code and commit quality through a series of automated tools and workflows. This ensures consistency, readability, and a stable codebase. ## Static Analysis Static analysis tools check your code for errors and style issues without running it. * **Biome**: Used for both linting (finding potential bugs) and formatting (enforcing a consistent code style). The configuration is centralized in the `@repo/biome-config` package, ensuring all code in the monorepo looks and feels the same. * **TypeScript**: Shared `tsconfig.json` files in the `@repo/typescript-config` package provide a strict, consistent set of compiler rules for all projects. ## Automated Quality Gates To ensure that no low-quality code enters the main branch, we use automated checks that run before every commit. ### The Pre-commit Hook This is powered by [husky](https://typicode.github.io/husky/), a tool that makes it easy to manage Git hooks. The configuration in `.husky/pre-commit` specifies a set of commands that must pass before a commit is allowed: 1. **`pnpm lint-staged`**: This command runs `biome check --write` on all staged files. It automatically formats your code and checks for linting errors. 2. **`pnpm typecheck`**: This runs the TypeScript compiler across the entire project to ensure there are no type errors. If either of these steps fails, the commit is aborted, giving you a chance to fix the issues. ### Commit Message Hygiene We use [commitlint](https://commitlint.js.org/) to enforce the [Conventional Commits](https://www.conventionalcommits.org/) specification. This means your commit messages must follow a standard format, like: ``` feat: add user profile page fix(auth): correct validation logic for email sign-up chore: update dependencies ``` This practice creates a clean, readable, and easily searchable Git history, and it enables automated tools to generate changelogs. # Monorepo (/docs/monorepo) ## Overview This project is structured as a [monorepo](https://monorepo.tools/), which means it houses multiple, distinct projects (applications and libraries) within a single Git repository. This approach has several key advantages for a project of this scale. ## Why a Monorepo? * **Code Sharing**: Seamlessly share code (like the `@repo/database` package) between applications without publishing to a private registry. * **Atomic Commits**: Changes to multiple parts of the system (e.g., updating a shared package and the applications that use it) can be made in a single, atomic commit. * **Simplified Dependency Management**: A single `pnpm-lock.yaml` file at the root manages dependencies for the entire project, ensuring consistency. * **Unified Tooling**: Run commands like `lint`, `build`, and `test` across the entire project from a single place. ## The `apps` vs. `packages` Philosophy The monorepo is organized into two main directories: * `apps/`: Contains the deployable applications. These are the user-facing parts of the system, like the `auth` server, the `api` server, and this documentation site. * `packages/`: Contains shared libraries and configurations. These are the building blocks that the applications depend on, such as the database client (`@repo/database`) and shared configurations (`@repo/biome-config`). DB API --> DB MCP --> DB `} /> ## Tooling Two key tools power this monorepo: ### 1. pnpm Workspaces [pnpm](https://pnpm.io/) is a fast and disk-space-efficient package manager. Its workspace feature is what allows us to manage multiple projects within this single repository. It hoists all dependencies to the root `node_modules` directory and uses symlinks to make the shared packages available to the applications that need them. ### 2. Turborepo [Turborepo](https://turborepo.org/) is a high-performance build system for JavaScript and TypeScript codebases. It sits on top of `pnpm` workspaces and intelligently orchestrates how tasks (like `build` and `lint`) are executed. * **Caching**: Turborepo caches the output of tasks. If you run `pnpm build` and haven't changed any files in a specific package, Turborepo will restore the output from its cache instead of re-building it, saving significant time. * **Task Orchestration**: It understands the dependencies between your packages and runs tasks in the correct order. For example, it will build `@repo/database` before it builds an application that depends on it. This is configured in the `turbo.json` file at the root of the project. # Authentication (/docs/authentication) ## Overview This starter kit features a secure, scalable, and decoupled authentication architecture powered by [Better Auth](https://www.better-auth.com/). This guide explains the overall design and the separation of concerns between the Auth Server and Resource Servers. ## Architecture: Decoupled Auth Server Instead of embedding authentication logic within the main API server, this project uses a dedicated, standalone **Auth Server** (`apps/auth`). All other backend servers (like `apps/api` and `apps/mcp`) are considered **Resource Servers**. This separation provides several advantages: * **Single Responsibility**: The Auth Server does one thing and does it well: authenticating users and issuing tokens. * **Scalability**: The Auth Server can be scaled independently of the resource servers. * **Security**: Resource servers don't need access to user credentials or session secrets. They only need to know how to validate a token. ### Auth Server Responsibilities The Auth Server is the central authority for user identity and authentication. Its primary duties include: * Handling user registration, login, logout, and password management. * Managing user sessions and issuing authentication tokens. * Providing public keys (via JWKS endpoint) for token verification. * Storing user data in a secure database. The Auth Server operates independently and does not contain any domain-specific business logic. ### Resource Server Responsibilities Resource Servers focus solely on their domain functionality, such as API endpoints or MCP services. They delegate all authentication concerns to the Auth Server: * Receiving and validating JWT tokens from clients. * Fetching and caching public keys from the Auth Server's JWKS endpoint for token verification. * Denying access to unauthorized requests. This allows Resource Servers to remain lightweight and focused on their core purposes. ### Server Interaction Communication between the Auth Server and Resource Servers is stateless and secure: * Clients authenticate with the Auth Server to obtain JWTs. * Clients include JWTs in requests to Resource Servers. * Resource Servers verify JWT signatures using keys from the Auth Server. This decoupled design enables easy scaling, independent deployments, and enhanced security by isolating authentication logic. Auth Server Note
Handles authentication and token issuance:
- User registration/login
- Session management
- JWT creation
- JWKS endpoint") NoteAPI("API Server Note
Focuses on business logic and validates JWTs") NoteMCP("MCP Server Note
Provides MCP services and validates JWTs") Clients[Clients
Web/Mobile Apps] -- "1. Authenticate" --> Auth Auth -- "2. Receive JWT" --> Clients Clients -- "3. Access Resource with JWT" --> API Clients -- "4. Access Resource with JWT" --> MCP API -.->|Verify JWT | Auth MCP -.->|Verify JWT| Auth %% Position the notes with invisible links Auth --- NoteAuth API --- NoteAPI MCP --- NoteMCP %% Make the positioning links invisible linkStyle 6 stroke-width:0px linkStyle 7 stroke-width:0px linkStyle 8 stroke-width:0px `} /> ## Replacing the Auth Server with Managed Services Due to the decoupled architecture, you can easily replace the self-hosted Auth Server with a managed authentication service like Clerk, Auth0, or Firebase Auth. ### Steps to Replace 1. Choose a managed auth provider that supports JWT issuance and provides a JWKS endpoint. 2. Configure your Resource Servers to use the managed provider's JWKS endpoint instead of the local Auth Server's. 3. Update client applications to authenticate directly with the managed service. 4. Optionally, remove the `apps/auth` directory from your project. ### Configuration Changes For each Resource Server (e.g., `apps/api`, `apps/mcp`): * Update the JWKS URL in your JWT validation middleware to point to the managed service's JWKS endpoint. * Ensure the JWT claims match what your application expects. ### Example Providers * **Clerk**: JWKS endpoint available at `https://your-domain.clerk.accounts.dev/.well-known/jwks.json` * **Auth0**: JWKS endpoint at `https://your-domain.auth0.com/.well-known/jwks.json` * **Firebase**: Use Firebase Admin SDK for verification, or extract JWKS from their endpoints. This allows you to leverage managed services while keeping the Resource Servers unchanged. # DB Schema Management (/docs/db-schema) ## Overview This project uses a structured approach to database schema management that combines **auto-generated schemas** from authentication configuration with **manually defined schemas** for application data. This hybrid approach ensures type safety, maintainability, and flexibility. ## Schema Sources The database schema is managed through two complementary sources: 1. **Authentication Schemas**: Automatically generated from Better Auth configuration 2. **Application Schemas**: Manually defined schemas for your custom data models ## Architecture The schema management workflow looks like this: (apps/auth/src/lib/auth.ts)"] -->|"pnpm db:schema"| E["Generated Auth Schema
(packages/database/src/schema/auth.ts)"]; C["Custom Schemas
(packages/database/src/schema/resources.ts)"] -->|"pnpm db:generate"| F["SQL Migrations
(packages/database/drizzle/migrations/)"]; E -->|"pnpm db:generate"| F; F -->|"pnpm db:migrate"| H[PostgreSQL Database]; `} /> ## Workflow ### Adding Authentication Features When you modify authentication settings: ```bash # 1. Update Better Auth configuration # Edit apps/auth/src/lib/auth.ts to add fields, plugins, etc. # 2. Generate updated auth schema pnpm db:schema # 3. Generate and apply migration pnpm db:generate && pnpm db:migrate ``` ### Adding Custom Data Models When you need new tables for your application: ```typescript // Edit packages/database/src/schema/resources.ts export const posts = table("posts", { id: serial("id").primaryKey(), title: text("title").notNull(), content: text("content"), authorId: text("author_id").references(() => users.id), createdAt: timestamp("created_at").defaultNow(), }); // Export from index.ts export * from "./resources"; ``` ```bash # Generate and apply migration pnpm db:generate && pnpm db:migrate ``` ## Benefits * **Type Safety**: Full TypeScript types generated for all schemas * **Zero Boilerplate**: Auth schemas generated automatically * **Version Control**: All schema changes tracked in Git * **Migration Safety**: Drizzle ensures safe, reversible migrations * **Flexibility**: Add custom tables without touching auth logic ## Best Practices * Always review generated SQL before applying migrations * Test migrations on a copy of production data first * Use descriptive names for custom tables and columns * Keep authentication and application schemas logically separated * Commit schema changes and migrations together ## Complete Setup For new projects, set up the database with: ```bash pnpm db:setup # Generates auth schema, creates migrations, and applies them ``` # Tech Stack (/docs/tech-stack) ## Overview This section outlines the key technologies used in this starter kit, along with the reasoning behind each choice. The tech stack is designed to prioritize type safety, developer experience, performance, and maintainability. ## Authentication ### Better Auth **Why [Better Auth](https://www.better-auth.com/)?** * Free, self-hostable and open-source * Modern, secure authentication library with excellent TypeScript support * Supports multiple authentication methods (email/password, OAuth, etc.) * Extensible plugin system for additional features **Usage**: Authentication and session management. **Alternatives**: Due to the [decoupled architecture](/docs/authentication#architecture-decoupled-auth-server), the Auth Server can be replaced with managed auth services like Clerk, Auth0, or Firebase Auth, which provide JWKS endpoints for JWT validation. See [Authentication](/docs/authentication#replacing-the-auth-server-with-managed-services) for details on replacing the Auth Server. ## Backend Frameworks ### Hono **Why [Hono](https://hono.dev/)?** * Lightweight and high-performance web framework * Excellent TypeScript support with full type inference * Built-in middleware system for authentication, logging, etc. * Minimalist API that's easy to learn and extend **Usage**: Framework for the Auth and API servers. **Framework Flexibility**: Due to the [decoupled architecture](/docs/authentication#architecture-decoupled-auth-server), resource servers can use any framework (e.g., NestJS, FastAPI, Gin, Rails), as long as they validate JWTs via JWKS. Note that non-JS frameworks may not work with Turborepo and Drizzle ORM is JS-based, so other languages connect directly to PostgreSQL using their own database libraries. ### FastMCP **Why [FastMCP](https://fastmcp.com/)?** * Specialized framework for building MCP (Model Context Protocol) servers * Optimized for AI agent integration * Lightweight and focused on RPC-style tool exposure * Demonstrates integration of non-Hono servers into the architecture **Usage**: Framework for the MCP server. ## Database & Data ### PostgreSQL **Why [PostgreSQL](https://postgresql.org/)?** * Robust, enterprise-grade relational database * Excellent JSON support for flexible data modeling * Strong ACID compliance and transactional integrity * Mature ecosystem with excellent tooling and community support **Usage**: Primary database for all data persistence. ### Drizzle ORM **Why [Drizzle](https://drizzle.team/)?** * Better Auth integration for automatic schema generation * Generates TypeScript types from database schema * Lightweight with zero runtime overhead * Excellent migration system with Drizzle Kit **Usage**: Database ORM and query builder. ## API Documentation ### Scalar **Why [Scalar](https://scalar.com/)?** * Beautiful, interactive API documentation * Auto-generates from OpenAPI specs * Built-in API testing capabilities * Modern UI that's easy to navigate and understand **Usage**: API documentation interface. ## Development Tools ### Docker **Why [Docker](https://docker.com/)?** * Consistent development environments across machines * Easy database setup and teardown * Containerized development workflow * Simplifies onboarding for new developers **Usage**: Running PostgreSQL database in development. Will be used as one of the deployment options for the whole stack. ### Drizzle Studio **Why [Drizzle Studio](https://drizzle.studio/)?** * Visual database interface for development * Query execution and schema exploration * Real-time database introspection * Integrated with Drizzle ORM for seamless workflow **Usage**: Database GUI for development and debugging. # TBA (/docs/deployment) TBA # Managing Dependencies (/docs/managing-dependencies) ## Overview This project uses [pnpm](https://pnpm.io/) and its [workspace](https://pnpm.io/workspaces) feature to manage dependencies across the monorepo. This guide explains how to add, remove, and update packages. ## Adding a Dependency To add a dependency to a specific application or package, use the `pnpm add` command with the `--filter` flag. ### Adding to an Application For example, to add `zod` to the `api` server: ```bash pnpm add zod --filter @repo/api-server ``` ### Adding to a Package To add a dev dependency like `@types/react` to the `@repo/database` package: ```bash pnpm add @types/react -D --filter @repo/database ``` * The `--filter` flag targets the workspace package by its `name` in its `package.json`. * Use `-D` to specify a development dependency. ## Adding a Workspace Package as a Dependency To make one package in the workspace a dependency of another (e.g., making `@repo/database` a dependency of `apps/api`), you can use the `workspace:*` protocol. In `apps/api/package.json`: ```json "dependencies": { "@repo/database": "workspace:*" } ``` Then, run `pnpm install` at the root of the project. `pnpm` will create the necessary symlinks. ## Removing a Dependency To remove a dependency, use the `pnpm remove` command, again with the `--filter` flag: ```bash pnpm remove zod --filter @repo/api-server ``` ## Updating Dependencies You can update dependencies interactively across the entire monorepo by running: ```bash pnpm update -i -r ``` * `-i` stands for interactive. * `-r` stands for recursive, applying the command to all packages in the workspace. # Biome Config (/docs/biome-config) **Location**: `packages/biome-config` ## Purpose This package provides a shared, centralized configuration for [Biome](https://biomejs.dev/), the project's all-in-one tool for linting and formatting. This creates a consistent code style and a single set of quality rules across the entire codebase. # Database (/docs/database) **Location**: `packages/database` ## Purpose This package is the single source of truth for all database-related concerns. It contains: * The Drizzle ORM client. * The complete database schema (both auto-generated and manual). * Database migration files and the Drizzle Kit configuration. Any application that needs to communicate with the database will use this package as a dependency. # TypeScript Config (/docs/typescript-config) **Location**: `packages/typescript-config` ## Purpose This package contains shared `tsconfig.json` base files. Different applications (e.g., a Next.js app vs. a Node.js server) may require slightly different TypeScript settings. This package provides a set of common, strict base configurations that other projects can extend. # API Server (/docs/api) **Location**: `apps/api` ## Purpose This application is the primary **Resource Server** for the starter kit. It is a lightweight and high-performance Hono server responsible for serving business-logic API endpoints. It is designed to be stateless and relies on the `auth` server for user authentication. ## Key Features * **Lightweight & Fast**: Built on Hono, a minimal and high-performance web framework. * **End-to-End Type Safety**: Leverages Zod for environment validation and route schemas. * **Self-Documenting**: Automatically generates interactive API documentation using `@hono/zod-openapi` and Scalar. * **Decoupled from Auth**: Securely validates JWTs without having any direct access to user credentials or session data. ## Project Structure The server's code is organized logically within `apps/api/src/`: * `index.ts`: The main server entry point. It initializes the Hono app, registers middleware, sets up routes, and starts the server. * `env.ts`: Uses `@t3-oss/env-core` and Zod to validate and type-define all environment variables at startup. This prevents runtime errors caused by missing or invalid configuration. * `docs/`: Contains all the logic for generating the OpenAPI specification and the Scalar UI. * `lib/`: Home to shared utilities, including JWT validation middleware (`jwt.ts`) and standardized error responses (`errors.ts`). * `routes/`: Each file in this directory defines a set of related API routes, keeping the codebase modular and easy to navigate. ## Core Patterns ### JWT Verification The `lib/jwt.ts` file contains the `jwtMiddleware`. This is a Hono middleware that: 1. Extracts the `Bearer` token from the `Authorization` header. 2. Uses the `jose` library to verify the token's signature against the public keys fetched from the `auth` server's JWKS endpoint. 3. Checks the token's `issuer` and `audience` to ensure it was issued by the correct authority for the correct purpose. 4. If valid, it attaches the token's payload to the request context (`c.set('jwtPayload', ...)`), making it available to downstream route handlers. This middleware is then applied to any route that requires authentication. ### Self-Documenting Routes Routes are defined using `@hono/zod-openapi`, which allows you to define the route's path, method, input/output schemas, and documentation all in one place. For example, in `routes/time.ts`: ```typescript const timeRoute = createRoute({ method: "get", path: "/time", summary: "Current server time (protected)", security: [{ bearerAuth: [] }], // Marks this as a protected route responses: { 200: { description: "OK", content: { "application/json": { schema: TimeResponseSchema } }, }, }, }); ``` This definition not only creates the route but also provides all the necessary information for `scalar.ts` to generate the beautiful, interactive API documentation. ## Environment Variables This server's environment variables are validated by `src/env.ts`. Refer to `apps/api/.env.example` for a template. * `PORT`: The port the server will run on (e.g., `3010`). * `RESOURCE_API_BASE_PATH`: The base path for all API routes (e.g., `/api/v1/resource`). * `JWKS_URL`: The full URL to the `auth` server's JWKS endpoint (e.g., `http://localhost:3001/api/v1/auth/jwks`). * `JWT_ISSUER`: The expected `iss` (issuer) claim in the JWT, which should be the base URL of the `auth` server. * `JWT_AUDIENCE`: The expected `aud` (audience) claim in the JWT, which should be the base URL of this API server. * `OPENAPI_SERVER_URLS`: A comma-separated list of base URLs for the OpenAPI documentation. ## Future Evolution The structure of this server is designed for easy extension. * **Adding New Routes**: Simply create a new file in the `routes/` directory, define your route schemas with Zod, and register it in `index.ts`. * **Scope-Based Authorization**: The `lib/jwt.ts` file already includes a `requireScope` middleware. This is a starting point for a role-based access control (RBAC) system. By adding scopes (e.g., `read:time`, `write:data`) to your JWTs in the `auth` server, you can use this middleware to protect specific routes, ensuring that only users with the correct permissions can access them. # Auth Server (/docs/auth) **Location**: `apps/auth` ## Purpose This is the dedicated **Authentication Server** for the project. Built with Hono and powered by [Better Auth](https://www.better-auth.com/), its sole responsibility is to handle user authentication (sign-up, sign-in, sign-out) and issue tokens. It acts as the central authority for user identity. ## The Hybrid Token Flow The Auth Server employs a hybrid approach to support both traditional web applications and modern clients (like mobile apps or SPAs). * **Web Clients**: Use secure, `HttpOnly` session cookies for authenticating to the primary application. * **API/Mobile Clients**: Use short-lived JWT (JSON Web Token) Bearer Tokens for all API communication. This flow is illustrated below: Web & Mobile] end subgraph "Authentication" Auth[Auth Server] end subgraph "Backend Services" Resources[Resource Servers
API & MCP] end Client -- "1. Authenticate & get
Long-Lived Session Token" --> Auth Client -- "2. Exchange Session for
Short-Lived Access Token (JWT)" --> Auth Client -- "3. Access protected resources with
Access Token (JWT)" --> Resources Resources -.->|4. Verify JWT using
JWKS| Auth `} /> **Flow Description:** 1. **Authentication**: A user logs in against the Auth Server. A web client gets a session cookie, while a mobile client gets a session token. 2. **Token Issuance**: When a client needs to access a resource server, it makes an authenticated request to the Auth Server to get a short-lived JWT. 3. **API Access**: The client includes this JWT in the `Authorization` header for all requests to the resource servers. 4. **Verification**: The resource servers verify the JWT's signature by fetching public keys from the Auth Server's JWKS endpoint (`/api/v1/auth/jwks`). ## Security Considerations This architecture is designed with security in mind. Here are the key concepts and trade-offs: * **Stolen JWTs**: Because JWTs are stateless, a stolen token can be used by an attacker until it expires. **Our primary defense is keeping token lifetimes short (15 minutes)**. This limits the window of opportunity for an attacker. * **JWKS Caching**: Resource servers **must** cache the JWKS response from the Auth Server. Fetching the keys on every request would create a massive performance bottleneck. Standard libraries like `jose` handle this caching automatically. * **Concurrent Requests**: If multiple API requests are made when a JWT has just expired, it can lead to a race condition where multiple new tokens are requested. Advanced client-side interceptors can solve this by queuing requests while a single new token is fetched. ## Customization For more advanced use cases or to customize the authentication behavior, refer to the [Better Auth documentation](https://www.better-auth.com/docs). You can extend the Auth Server's functionality by modifying the Better Auth configuration in `apps/auth/src/auth.ts`. ## Environment Variables This server's environment variables are validated by `src/env.ts`. Refer to `apps/auth/.env.example` for a template. * `PORT`: The port the server will run on (e.g., `3001`). * `NODE_ENV`: The runtime environment (`development` or `production`). * `DATABASE_URL`: The full connection string for the PostgreSQL database. * `BETTER_AUTH_URL`: The public base URL of this authentication server. * `BETTER_AUTH_SECRET`: A secret key (at least 32 characters long) used for signing sessions and tokens. # MCP Server (/docs/mcp) **Location**: `apps/mcp` ## Overview This application is a specialized **Resource Server** built with FastMCP. It is designed to expose "tools" that can be called by AI agents. It serves as a practical example of how a non-Hono, RPC-style server can integrate into the project's authentication architecture by consuming JWTs. ## Key Features * **Purpose-Built for AI**: Designed to expose "tools" (RPC-style functions) that AI agents can call. * **Lightweight**: Minimalist and focused on performance. * **JWT Consumer**: Demonstrates how a non-Hono server can validate JWTs issued by the `auth` server. ## Project Structure The server's logic is primarily contained in `apps/mcp/src/index.ts`. It defines: * An `authenticate` function that extracts the JWT from the `Authorization` header. * A series of "tools" that can be called by clients. * A `canAccess` guard on protected tools to ensure a valid JWT is present. ## Core Patterns ### Tool-Level Authentication Unlike the `api` server, which uses middleware to protect entire routes, the `mcp` server demonstrates a more granular, tool-level authentication pattern. Each tool definition can include a `canAccess` function. This function receives the authentication data (in this case, the session data containing the JWT) and returns `true` or `false` to grant or deny access. ```typescript // From apps/mcp/src/index.ts // Protected tool: require JWT server.addTool({ name: "get_time", description: "Get the current server time (requires JWT authentication)", // This function acts as a guard for the tool canAccess: (auth): boolean => Boolean((auth as SessionData | undefined)?.jwt), async execute(_args, { session }) { // ... execution logic }, }); ``` This pattern is useful when a single server needs to expose both public and private tools. ### A Second JWT Consumer While the `mcp` server itself doesn't perform the JWT *validation* (it delegates that to the tools it calls, like `handleGetTime`), it demonstrates the client-side of the pattern: it expects a JWT and passes it along. This reinforces the decoupled architecture, showing that any service, regardless of its framework, can participate in the authentication model as long as it understands how to handle a Bearer Token. ## Environment Variables This server's environment variables are validated by `src/env.ts`. Refer to `apps/mcp/.env.example` for a template. * `MCP_SERVER_PORT`: The port the server will run on (e.g., `7411`). * `RESOURCE_API_URL`: The base URL of the `api` server, which this server's tools may call.