From 6e6815a5faadf4f6df804eb8fef90f92f3cf5441 Mon Sep 17 00:00:00 2001 From: Wuesteon Date: Tue, 16 Dec 2025 02:45:41 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20docs(auth):=20document=20Better?= =?UTF-8?q?=20Auth=20typing=20improvements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add comprehensive documentation for Better Auth improvements: - Centralized types package usage guide - Frontend type inference examples - Zod validation implementation - Rate limiting configuration - Integration test documentation - Migration guide for developers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- services/mana-core-auth/CLAUDE.md | 32 + .../docs/BETTER_AUTH_TYPING_IMPROVEMENTS.md | 803 ++++++++++++++++++ 2 files changed, 835 insertions(+) create mode 100644 services/mana-core-auth/docs/BETTER_AUTH_TYPING_IMPROVEMENTS.md diff --git a/services/mana-core-auth/CLAUDE.md b/services/mana-core-auth/CLAUDE.md index d7d321613..0b6a09904 100644 --- a/services/mana-core-auth/CLAUDE.md +++ b/services/mana-core-auth/CLAUDE.md @@ -117,8 +117,10 @@ Key points: | ------------------------------------------ | ------------------------------------------------ | | `src/auth/better-auth.config.ts` | Better Auth configuration with JWT + Org plugins | | `src/auth/services/better-auth.service.ts` | Main auth service - ALL auth logic here | +| `src/auth/types/better-auth.types.ts` | Type definitions (inferred + manual) | | `src/db/schema/auth.schema.ts` | User, session, account, jwks tables | | `docs/AUTHENTICATION_ARCHITECTURE.md` | Comprehensive auth documentation | +| `docs/BETTER_AUTH_TYPING_IMPROVEMENTS.md` | TypeScript typing decisions and limitations | ## Environment Variables @@ -157,6 +159,36 @@ Other services call `POST /api/v1/auth/validate` with the JWT. The validation us For dynamic data (credits, org info), create API endpoints instead. +### Better Auth TypeScript Types + +**READ FIRST:** `docs/BETTER_AUTH_TYPING_IMPROVEMENTS.md` + +**Prefer inferred types:** +```typescript +import type { AuthUser, AuthSession } from '../better-auth.config'; +``` + +**Known limitation:** `$Infer` doesn't expose plugin API methods. The manual `BetterAuthAPI` interface is required: +```typescript +// This is necessary - Better Auth's $Infer doesn't work for API methods +private get api(): BetterAuthAPI { + return this.auth.api as unknown as BetterAuthAPI; +} +``` + +**Adding user fields:** +```typescript +// In better-auth.config.ts +user: { + additionalFields: { + myField: { + type: 'string', + input: false, // SECURITY: prevents client from setting + }, + }, +}, +``` + ## Debugging ### Token not validating? diff --git a/services/mana-core-auth/docs/BETTER_AUTH_TYPING_IMPROVEMENTS.md b/services/mana-core-auth/docs/BETTER_AUTH_TYPING_IMPROVEMENTS.md new file mode 100644 index 000000000..9c44387cc --- /dev/null +++ b/services/mana-core-auth/docs/BETTER_AUTH_TYPING_IMPROVEMENTS.md @@ -0,0 +1,803 @@ +# Better Auth Typing Improvements + +**Date:** December 2024 +**Status:** Implemented +**Version:** 2.0 + +--- + +## Table of Contents + +1. [Executive Summary](#executive-summary) +2. [Centralized Types Package](#centralized-types-package) +3. [Frontend Type Inference](#frontend-type-inference) +4. [Zod Validation for Role Enum](#zod-validation-for-role-enum) +5. [Rate Limiting on Sensitive Endpoints](#rate-limiting-on-sensitive-endpoints) +6. [Package Migrations](#package-migrations) +7. [Integration Tests](#integration-tests) +8. [Test Infrastructure](#test-infrastructure) +9. [Known Limitations](#known-limitations) +10. [Migration Guide](#migration-guide) +11. [References](#references) + +--- + +## Executive Summary + +This document describes the Better Auth typing improvements implemented in December 2024. The changes establish a robust, type-safe authentication system with: + +| Improvement | Description | +|-------------|-------------| +| **Centralized Types** | Single source of truth via `@manacore/better-auth-types` | +| **Frontend Inference** | `userAdditionalFields` export for Better Auth client plugins | +| **Runtime Validation** | Zod schema validates role enum server-side | +| **Rate Limiting** | `@Throttle` decorators protect sensitive auth endpoints | +| **Integration Tests** | 8 comprehensive tests for role security | +| **ESM Compatibility** | `jose` mock for Jest in ESM environment | + +### Key Files Modified + +| File | Purpose | +|------|---------| +| `packages/better-auth-types/src/index.ts` | Centralized type definitions | +| `services/mana-core-auth/src/auth/better-auth.config.ts` | Zod validation, role field config | +| `services/mana-core-auth/src/auth/auth.controller.ts` | Rate limiting decorators | +| `packages/shared-auth/src/better-auth-fields.ts` | Frontend type inference exports | +| `packages/shared-nestjs-auth/src/types/index.ts` | NestJS guard types | +| `services/mana-core-auth/test/__mocks__/jose.ts` | ESM-compatible JWT mock | +| `services/mana-core-auth/test/integration/role-security.e2e-spec.ts` | Role security tests | + +--- + +## Centralized Types Package + +### Overview + +A new package `@manacore/better-auth-types` provides all shared Better Auth types for the monorepo. This eliminates type duplication and ensures consistency across all services. + +**Package Location:** `packages/better-auth-types/` + +### Package Structure + +``` +packages/better-auth-types/ +├── src/ +│ └── index.ts # All type exports +├── dist/ # Built output +├── package.json +└── tsconfig.json +``` + +### Available Types + +#### User Role Types + +```typescript +import type { UserRole } from '@manacore/better-auth-types'; +import { isValidUserRole } from '@manacore/better-auth-types'; + +// UserRole = 'user' | 'admin' | 'service' +const role: UserRole = 'admin'; + +// Runtime validation +if (isValidUserRole(unknownValue)) { + // unknownValue is now typed as UserRole +} +``` + +#### JWT Payload Types + +```typescript +import type { JWTPayload, StrictJWTPayload } from '@manacore/better-auth-types'; + +// JWTPayload - role as string (flexible) +interface JWTPayload { + sub: string; + email: string; + role: string; // Any string + sid: string; + exp?: number; + iat?: number; + iss?: string; + aud?: string; +} + +// StrictJWTPayload - role as UserRole (strict) +interface StrictJWTPayload { + sub: string; + email: string; + role: UserRole; // 'user' | 'admin' | 'service' + sid: string; + // ... +} +``` + +#### NestJS Guard Types + +```typescript +import type { CurrentUserData, StrictCurrentUserData } from '@manacore/better-auth-types'; +import { jwtPayloadToCurrentUser, jwtPayloadToStrictCurrentUser } from '@manacore/better-auth-types'; + +// Use in controller +@Get('profile') +@UseGuards(JwtAuthGuard) +getProfile(@CurrentUser() user: CurrentUserData) { + return { userId: user.userId, email: user.email, role: user.role }; +} +``` + +#### Utility Functions + +```typescript +import { + isValidUserRole, + isValidOrganizationRole, + jwtPayloadToCurrentUser, + jwtPayloadToStrictCurrentUser, +} from '@manacore/better-auth-types'; + +// Convert JWT payload to current user data +const currentUser = jwtPayloadToCurrentUser(payload); + +// Strict conversion (returns null if role invalid) +const strictUser = jwtPayloadToStrictCurrentUser(payload); +if (strictUser === null) { + throw new Error('Invalid role in JWT'); +} +``` + +### Full Type Export List + +| Type/Function | Purpose | +|---------------|---------| +| `UserRole` | `'user' \| 'admin' \| 'service'` | +| `OrganizationRole` | `'owner' \| 'admin' \| 'member'` | +| `InvitationStatus` | `'pending' \| 'accepted' \| 'rejected' \| 'expired'` | +| `JWTPayload` | Standard JWT payload interface | +| `StrictJWTPayload` | JWT payload with strict UserRole | +| `UserData` | User data for client apps | +| `StrictUserData` | User data with strict UserRole | +| `CurrentUserData` | NestJS guard user data | +| `StrictCurrentUserData` | NestJS guard user data with strict UserRole | +| `AuthResult` | Auth operation result | +| `TokenRefreshResult` | Token refresh operation result | +| `TokenValidationResponse` | Token validation response | +| `Organization` | Organization data structure | +| `OrganizationMember` | Organization member data | +| `OrganizationInvitation` | Invitation data | +| `CreditBalance` | Credit balance info | +| `B2BInfo` | B2B information from JWT | +| `userAdditionalFields` | Client type inference config | +| `isValidUserRole()` | Runtime role validation | +| `isValidOrganizationRole()` | Runtime org role validation | +| `jwtPayloadToCurrentUser()` | Convert JWT to CurrentUserData | +| `jwtPayloadToStrictCurrentUser()` | Convert JWT to StrictCurrentUserData | + +--- + +## Frontend Type Inference + +### Overview + +Better Auth's `inferAdditionalFields` plugin allows frontend clients to have proper TypeScript inference for custom user fields like `role`. The `userAdditionalFields` export provides the configuration for this. + +### Location + +**Primary:** `packages/better-auth-types/src/index.ts` +**Re-export:** `packages/shared-auth/src/better-auth-fields.ts` + +### Usage in Frontend Apps + +#### SvelteKit Example + +```typescript +// src/lib/auth.ts +import { createAuthClient } from "better-auth/client"; +import { inferAdditionalFields } from "better-auth/client/plugins"; +import { userAdditionalFields } from "@manacore/shared-auth"; + +export const authClient = createAuthClient({ + baseURL: "http://localhost:3001", + plugins: [inferAdditionalFields(userAdditionalFields)], +}); + +// Now user.role is properly typed! +const session = await authClient.getSession(); +if (session?.user) { + console.log(session.user.role); // TypeScript knows this is string +} +``` + +#### React/React Native Example + +```typescript +// src/auth/client.ts +import { createAuthClient } from "better-auth/client"; +import { inferAdditionalFields } from "better-auth/client/plugins"; +import { userAdditionalFields } from "@manacore/shared-auth"; + +export const auth = createAuthClient({ + baseURL: process.env.EXPO_PUBLIC_AUTH_URL, + plugins: [inferAdditionalFields(userAdditionalFields)], +}); +``` + +### Field Definition Structure + +The `userAdditionalFields` object must match the server-side configuration: + +```typescript +// packages/better-auth-types/src/index.ts +export const userAdditionalFields = { + user: { + role: { + type: 'string' as const, + }, + }, +} as const; +``` + +**IMPORTANT:** Keep this in sync with the server config in `services/mana-core-auth/src/auth/better-auth.config.ts`. + +--- + +## Zod Validation for Role Enum + +### Overview + +Runtime validation ensures only valid role values can be assigned to users. This provides defense-in-depth alongside `input: false`. + +### Location + +**File:** `services/mana-core-auth/src/auth/better-auth.config.ts` (lines 27-51) + +### Implementation + +```typescript +import { z } from 'zod'; + +/** + * User role schema with Zod runtime validation + */ +export const userRoleSchema = z.enum(['user', 'admin', 'service'], { + errorMap: () => ({ message: 'Invalid user role. Must be one of: user, admin, service' }), +}); + +/** + * Inferred TypeScript type from Zod schema + */ +export type UserRole = z.infer; + +/** + * Type guard using Zod + */ +export function isValidUserRole(role: unknown): role is UserRole { + return userRoleSchema.safeParse(role).success; +} +``` + +### Better Auth Integration + +The Zod schema is used in the `user.additionalFields` configuration: + +```typescript +// services/mana-core-auth/src/auth/better-auth.config.ts +user: { + additionalFields: { + role: { + type: 'string', + required: false, + defaultValue: 'user', + input: false, // Security: clients cannot set role + validator: { + input: userRoleSchema, // Runtime validation with Zod + }, + }, + }, +}, +``` + +### Security Layers + +| Layer | Protection | +|-------|------------| +| `input: false` | Prevents clients from setting role during registration | +| `defaultValue: 'user'` | New users always start with 'user' role | +| `validator.input` | Rejects invalid role values server-side | +| Database constraint | PostgreSQL enum ensures data integrity | + +--- + +## Rate Limiting on Sensitive Endpoints + +### Overview + +Rate limiting protects against brute force attacks, credential stuffing, and enumeration attacks on authentication endpoints. + +### Location + +**File:** `services/mana-core-auth/src/auth/auth.controller.ts` (lines 26-44) + +### Rate Limit Configuration + +```typescript +const RATE_LIMITS = { + /** 5 login attempts per 60 seconds */ + LOGIN: { limit: 5, ttl: 60000 }, + /** 10 registrations per hour */ + REGISTER: { limit: 10, ttl: 3600000 }, + /** 3 password reset requests per 5 minutes */ + PASSWORD_RESET: { limit: 3, ttl: 300000 }, + /** 5 B2B registrations per hour */ + B2B_REGISTER: { limit: 5, ttl: 3600000 }, +} as const; +``` + +### Endpoint Rate Limits + +| Endpoint | Limit | TTL | Purpose | +|----------|-------|-----|---------| +| `POST /auth/login` | 5/min | 60s | Brute force protection | +| `POST /auth/register` | 10/hr | 1hr | Spam prevention | +| `POST /auth/forgot-password` | 3/5min | 5min | Email enumeration protection | +| `POST /auth/register/b2b` | 5/hr | 1hr | B2B spam prevention | +| `POST /auth/validate` | No limit | - | High-frequency internal operation | +| `GET /auth/jwks` | No limit | - | Cacheable public keys | + +### Usage in Controller + +```typescript +import { Throttle, SkipThrottle } from '@nestjs/throttler'; + +@Controller('auth') +export class AuthController { + /** + * Rate limit: 5 attempts per minute per IP + */ + @Post('login') + @Throttle({ default: RATE_LIMITS.LOGIN }) + @HttpCode(HttpStatus.OK) + async login(@Body() loginDto: LoginDto) { + return this.betterAuthService.signIn(loginDto); + } + + /** + * Skip rate limiting for high-frequency internal operations + */ + @Post('validate') + @SkipThrottle() + @HttpCode(HttpStatus.OK) + async validate(@Body() body: { token: string }) { + return this.betterAuthService.validateToken(body.token); + } +} +``` + +### Rate Limit Response + +When rate limit is exceeded, the API returns: + +```json +{ + "statusCode": 429, + "message": "ThrottlerException: Too Many Requests" +} +``` + +--- + +## Package Migrations + +### @manacore/shared-auth + +**Purpose:** Client-side auth utilities for web/mobile apps + +**Migration:** Now re-exports types from `@manacore/better-auth-types` + +**File:** `packages/shared-auth/src/better-auth-fields.ts` + +```typescript +// Re-export from centralized package +export { + userAdditionalFields, + type UserRole, + type OrganizationRole, + type UserWithAdditionalFields, + isValidUserRole, + isValidOrganizationRole, +} from '@manacore/better-auth-types'; +``` + +**File:** `packages/shared-auth/src/index.ts` + +```typescript +// Better Auth field definitions for client type inference +export { + userAdditionalFields, + type UserRole, + type OrganizationRole, + type UserWithAdditionalFields, + isValidUserRole, + isValidOrganizationRole, +} from './better-auth-fields'; +``` + +### @manacore/shared-nestjs-auth + +**Purpose:** NestJS guards and decorators for JWT validation + +**Migration:** Now uses `@manacore/better-auth-types` as a dependency + +**File:** `packages/shared-nestjs-auth/package.json` + +```json +{ + "dependencies": { + "@manacore/better-auth-types": "workspace:*" + } +} +``` + +**File:** `packages/shared-nestjs-auth/src/types/index.ts` + +```typescript +// Re-export centralized types +export type { + CurrentUserData, + StrictCurrentUserData, + JWTPayload, + StrictJWTPayload, + UserRole, + OrganizationRole, + TokenValidationResponse, +} from '@manacore/better-auth-types'; + +export { + isValidUserRole, + isValidOrganizationRole, + jwtPayloadToCurrentUser, + jwtPayloadToStrictCurrentUser, +} from '@manacore/better-auth-types'; +``` + +--- + +## Integration Tests + +### Overview + +Comprehensive integration tests verify the security of the role field implementation. + +### Location + +**File:** `services/mana-core-auth/test/integration/role-security.e2e-spec.ts` + +### Test Categories + +#### 1. Role Field Security (`input: false`) + +| Test | Description | +|------|-------------| +| Default role assignment | New users get `'user'` role | +| Input security | Role field in registration body is ignored | +| JWT payload role | JWT contains correct role after login | + +#### 2. Role Validation + +| Test | Description | +|------|-------------| +| Valid enum values | Role is one of `['user', 'admin', 'service']` | +| Token refresh preservation | Role persists across token refresh (skipped in mock env) | + +#### 3. Session and Role Consistency + +| Test | Description | +|------|-------------| +| Multiple sessions | Same user has same role across sessions | +| JWT claims completeness | JWT contains `sub`, `email`, `role`, `sid` | + +#### 4. JWT Payload Minimalism + +| Test | Description | +|------|-------------| +| No sensitive data | JWT does not contain `password`, `creditBalance`, etc. | + +### Running Tests + +```bash +# From mana-core-auth directory +pnpm test:e2e + +# Run specific test file +pnpm test:e2e -- --testPathPattern=role-security +``` + +### Sample Test + +```typescript +it('should ignore role field in registration body (input: false security)', async () => { + const uniqueEmail = `role-escalation-attempt-${Date.now()}@example.com`; + + // Attempt to register with admin role (should be ignored) + await betterAuthService.registerB2C({ + email: uniqueEmail, + password: 'SecurePassword123!', + name: 'Escalation Attempt User', + // Note: If someone tries to add role: 'admin' to the request body, + // Better Auth's input: false should ignore it + }); + + // Login to verify the role + const loginResult = await betterAuthService.signIn({ + email: uniqueEmail, + password: 'SecurePassword123!', + }); + + // Role should always be 'user' (the default), not 'admin' + expect(loginResult.user.role).toBe('user'); +}); +``` + +--- + +## Test Infrastructure + +### Jose Mock for ESM Compatibility + +Jest has issues with ESM modules like `jose`. A mock implementation provides test compatibility. + +### Location + +**File:** `services/mana-core-auth/test/__mocks__/jose.ts` + +### Mock Implementation + +```typescript +// Mock JWT payload interface +export interface JWTPayload { + sub?: string; + email?: string; + role?: string; + sessionId?: string; + sid?: string; + iat?: number; + exp?: number; + iss?: string; + aud?: string | string[]; + [key: string]: unknown; +} + +// Mock jwtVerify function +export const jwtVerify = jest.fn( + async (token: string, _keySet: MockKeySet, _options?: unknown): Promise => { + // For tests, decode the token if it's a valid JWT format + try { + const parts = token.split('.'); + if (parts.length === 3) { + const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString()); + return { + payload, + protectedHeader: { alg: 'EdDSA', typ: 'JWT' }, + }; + } + } catch { + // If decoding fails, return mock data + } + + // Return mock payload for invalid/test tokens + return { + payload: { + sub: 'test-user-id', + email: 'test@example.com', + role: 'user', + sessionId: 'test-session-id', + sid: 'test-session-id', + iat: Math.floor(Date.now() / 1000), + exp: Math.floor(Date.now() / 1000) + 3600, + iss: 'manacore', + aud: 'manacore', + }, + protectedHeader: { alg: 'EdDSA', typ: 'JWT' }, + }; + } +); + +// Mock createRemoteJWKSet function +export const createRemoteJWKSet = jest.fn((url: URL) => { + return new MockKeySet(url); +}); + +// Mock error classes +export class JOSEError extends Error { /* ... */ } +export class JWTExpired extends JOSEError { /* ... */ } +export class JWTInvalid extends JOSEError { /* ... */ } + +export const errors = { JOSEError, JWTExpired, JWTInvalid }; +``` + +### Jest Configuration + +Add to Jest config to use the mock: + +```javascript +// jest.config.js +module.exports = { + moduleNameMapper: { + '^jose$': '/test/__mocks__/jose.ts', + }, +}; +``` + +--- + +## Known Limitations + +### 1. Better Auth $Infer for API Methods + +Better Auth's `$Infer` pattern does not expose plugin API methods. The inferred `AuthAPI` type is incomplete. + +**Impact:** Manual `BetterAuthAPI` interface is still required in `better-auth.types.ts`. + +**Workaround:** + +```typescript +// Must cast to manual interface +private get api(): BetterAuthAPI { + return this.auth.api as unknown as BetterAuthAPI; +} +``` + +### 2. Client Type Inference vs Server Config + +The `userAdditionalFields` export must be kept in sync with the server configuration manually. + +**Mitigation:** Documentation and code comments reference the server config file. + +### 3. Token Refresh Test in Mock Environment + +The token refresh test is skipped because it requires a real database connection. + +```typescript +it.skip('should preserve role across token refresh', async () => { + // Requires real database for session validation +}); +``` + +### 4. Email Service Not Implemented + +Password reset sends to console log, not actual email. + +```typescript +sendResetPassword: async ({ user, url, token }) => { + console.log('[Password Reset] User:', user.email); + console.log('[Password Reset] Reset URL:', url); + // TODO: Implement email service +}; +``` + +--- + +## Migration Guide + +### For Backend Developers + +1. **Update imports to use centralized types:** + +```typescript +// Before +import { JWTPayload } from '../types/jwt.types'; + +// After +import type { JWTPayload, CurrentUserData } from '@manacore/better-auth-types'; +``` + +2. **Use type guards for runtime validation:** + +```typescript +import { isValidUserRole } from '@manacore/better-auth-types'; + +if (!isValidUserRole(payload.role)) { + throw new UnauthorizedException('Invalid role'); +} +``` + +### For Frontend Developers + +1. **Add type inference to auth client:** + +```typescript +import { createAuthClient } from "better-auth/client"; +import { inferAdditionalFields } from "better-auth/client/plugins"; +import { userAdditionalFields } from "@manacore/shared-auth"; + +export const authClient = createAuthClient({ + baseURL: "http://localhost:3001", + plugins: [inferAdditionalFields(userAdditionalFields)], +}); +``` + +2. **Access typed user fields:** + +```typescript +const session = await authClient.getSession(); +if (session?.user) { + const role = session.user.role; // TypeScript knows this is string +} +``` + +### For Test Writers + +1. **Use the jose mock for JWT tests:** + +```typescript +// Jest automatically uses the mock from test/__mocks__/jose.ts +import { jwtVerify } from 'jose'; + +// The mock returns predictable test data +const result = await jwtVerify(token, jwks); +expect(result.payload.role).toBe('user'); +``` + +2. **Write integration tests for role security:** + +```typescript +it('should prevent role escalation', async () => { + // Register user (role cannot be set via API) + await betterAuthService.registerB2C({ email, password, name }); + + // Login and verify role is 'user' + const result = await betterAuthService.signIn({ email, password }); + expect(result.user.role).toBe('user'); +}); +``` + +--- + +## References + +### Official Documentation + +- [Better Auth TypeScript Guide](https://www.better-auth.com/docs/concepts/typescript) +- [Better Auth Database Guide](https://www.better-auth.com/docs/concepts/database) +- [Better Auth JWT Plugin](https://www.better-auth.com/docs/plugins/jwt) +- [NestJS Throttler](https://docs.nestjs.com/security/rate-limiting) +- [Zod Documentation](https://zod.dev/) + +### Internal Files + +| File | Purpose | +|------|---------| +| `packages/better-auth-types/src/index.ts` | Centralized type definitions | +| `services/mana-core-auth/src/auth/better-auth.config.ts` | Server-side auth configuration | +| `services/mana-core-auth/src/auth/auth.controller.ts` | Auth endpoints with rate limiting | +| `services/mana-core-auth/src/auth/types/better-auth.types.ts` | Legacy types (deprecated) | +| `packages/shared-auth/src/better-auth-fields.ts` | Client type inference exports | +| `packages/shared-nestjs-auth/src/types/index.ts` | NestJS guard types | +| `services/mana-core-auth/test/__mocks__/jose.ts` | JWT mock for tests | +| `services/mana-core-auth/test/integration/role-security.e2e-spec.ts` | Role security tests | + +### GitHub Issues (Better Auth) + +- [#3780 - Type issue with auth.api.getSession](https://github.com/better-auth/better-auth/issues/3780) +- [#4875 - $Infer.Session doesn't respect customSession](https://github.com/better-auth/better-auth/issues/4875) +- [#5159 - Plugin fields not in TypeScript types](https://github.com/better-auth/better-auth/issues/5159) + +--- + +## Appendix: File Changes Summary + +| File | Changes | +|------|---------| +| `packages/better-auth-types/src/index.ts` | New file - all centralized types | +| `packages/better-auth-types/package.json` | New package configuration | +| `services/mana-core-auth/src/auth/better-auth.config.ts` | Added Zod validation, role field config | +| `services/mana-core-auth/src/auth/auth.controller.ts` | Added rate limiting decorators | +| `packages/shared-auth/src/better-auth-fields.ts` | Re-exports from centralized package | +| `packages/shared-auth/src/index.ts` | Updated exports | +| `packages/shared-nestjs-auth/src/types/index.ts` | Re-exports from centralized package | +| `packages/shared-nestjs-auth/package.json` | Added dependency | +| `services/mana-core-auth/test/__mocks__/jose.ts` | New mock for ESM compatibility | +| `services/mana-core-auth/test/integration/role-security.e2e-spec.ts` | New integration tests | + +**Breaking Changes:** None (backward compatible) +**Type Safety:** Significantly improved with centralized types and runtime validation