Backend: - Auth controller sets httpOnly secure cookies (access_token, refresh_token, goodgo_authenticated) on login/register/refresh - JWT strategy reads token from cookie first, falls back to Authorization header - Added POST /auth/logout to clear auth cookies - Added POST /auth/exchange-token for OAuth callback token-to-cookie exchange - Refresh endpoint reads refresh_token from cookie (body fallback for backwards compat) - CSRF middleware excludes auth endpoints (login, register, refresh, exchange-token, logout) Frontend: - Removed all localStorage token storage (goodgo_tokens key) - Removed authGet/authPost/authPatch helpers from api-client (tokens sent via cookies) - All API calls use credentials:'include' for cookie-based auth - Updated auth-store: no more token state, uses isAuthenticated flag from cookie - Updated admin-api, listings-api to remove explicit token parameters - Updated all pages (admin dashboard, users, KYC, moderation, listings) to remove token passing - OAuth callbacks use exchange-token endpoint to convert URL tokens to cookies - Auth provider simplified (no client-side cookie management needed) Security improvements: - JWT no longer accessible via JavaScript (XSS-safe) - Refresh token scoped to /auth path only - Server-side goodgo_authenticated cookie with SameSite=Lax - Access token cookie with SameSite=Strict Co-Authored-By: Paperclip <noreply@paperclip.ing>
63 lines
2.4 KiB
TypeScript
63 lines
2.4 KiB
TypeScript
import { Global, type MiddlewareConsumer, Module, type NestModule, RequestMethod } from '@nestjs/common';
|
|
import { APP_FILTER } from '@nestjs/core';
|
|
import { EventEmitterModule } from '@nestjs/event-emitter';
|
|
import { makeCounterProvider } from '@willsoto/nestjs-prometheus';
|
|
import { EventBusService } from './infrastructure/event-bus.service';
|
|
import { GlobalExceptionFilter } from './infrastructure/filters/global-exception.filter';
|
|
import { LoggerService } from './infrastructure/logger.service';
|
|
import { CorrelationIdMiddleware } from './infrastructure/middleware/correlation-id.middleware';
|
|
import { CsrfMiddleware } from './infrastructure/middleware/csrf.middleware';
|
|
import { RequestLoggingMiddleware } from './infrastructure/middleware/request-logging.middleware';
|
|
import { SanitizeInputMiddleware } from './infrastructure/middleware/sanitize-input.middleware';
|
|
import { PrismaService } from './infrastructure/prisma.service';
|
|
import { RedisService } from './infrastructure/redis.service';
|
|
import { CacheService, CACHE_HIT_TOTAL, CACHE_MISS_TOTAL } from './infrastructure/cache.service';
|
|
|
|
@Global()
|
|
@Module({
|
|
imports: [EventEmitterModule.forRoot()],
|
|
providers: [
|
|
PrismaService,
|
|
RedisService,
|
|
CacheService,
|
|
LoggerService,
|
|
EventBusService,
|
|
makeCounterProvider({
|
|
name: CACHE_HIT_TOTAL,
|
|
help: 'Total number of cache hits',
|
|
labelNames: ['resource'],
|
|
}),
|
|
makeCounterProvider({
|
|
name: CACHE_MISS_TOTAL,
|
|
help: 'Total number of cache misses',
|
|
labelNames: ['resource'],
|
|
}),
|
|
{
|
|
provide: APP_FILTER,
|
|
useClass: GlobalExceptionFilter,
|
|
},
|
|
],
|
|
exports: [PrismaService, RedisService, CacheService, LoggerService, EventBusService],
|
|
})
|
|
export class SharedModule implements NestModule {
|
|
configure(consumer: MiddlewareConsumer): void {
|
|
consumer
|
|
.apply(CorrelationIdMiddleware, SanitizeInputMiddleware, RequestLoggingMiddleware)
|
|
.forRoutes('*');
|
|
|
|
if (process.env['NODE_ENV'] !== 'test') {
|
|
consumer
|
|
.apply(CsrfMiddleware)
|
|
.exclude(
|
|
{ path: 'payments/callback/(.*)', method: RequestMethod.POST },
|
|
{ path: 'auth/login', method: RequestMethod.POST },
|
|
{ path: 'auth/register', method: RequestMethod.POST },
|
|
{ path: 'auth/refresh', method: RequestMethod.POST },
|
|
{ path: 'auth/exchange-token', method: RequestMethod.POST },
|
|
{ path: 'auth/logout', method: RequestMethod.POST },
|
|
)
|
|
.forRoutes('*');
|
|
}
|
|
}
|
|
}
|