mirror of
http://172.20.10.11:3000/gitadmin/INSIGHT-MVP.git
synced 2026-06-24 22:46:39 +02:00
Backend-driven Authorization Code Flow with @azure/msal-node: - EntraIdService: MSAL ConfidentialClientApplication, auth URL generation, token exchange - SsoController: /auth/sso/microsoft (initiate) + /auth/sso/microsoft/callback (callback) - AuthService.loginViaSso(): User provisioning (find by OID, auto-link by email, or create new) - CSRF protection via state parameter stored in Redis - SSO status endpoint for frontend feature detection Frontend: - "Mit Microsoft anmelden" button on login page (shown only when SSO is configured) - SsoCallbackPage: handles redirect from backend, sets token, loads user profile - AuthContext.loginWithToken(): new method for SSO token handling Configuration: - AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_REDIRECT_URI env vars - docker-compose.yml updated to pass Azure vars to core service Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
120 lines
2.1 KiB
TypeScript
120 lines
2.1 KiB
TypeScript
import { plainToInstance, Type } from 'class-transformer';
|
|
import {
|
|
IsEnum,
|
|
IsNotEmpty,
|
|
IsNumber,
|
|
IsOptional,
|
|
IsString,
|
|
Min,
|
|
Max,
|
|
validateSync,
|
|
} from 'class-validator';
|
|
|
|
enum Environment {
|
|
Development = 'development',
|
|
Production = 'production',
|
|
Test = 'test',
|
|
}
|
|
|
|
class EnvironmentVariables {
|
|
@IsEnum(Environment)
|
|
NODE_ENV: Environment = Environment.Development;
|
|
|
|
@Type(() => Number)
|
|
@IsNumber()
|
|
@Min(1)
|
|
@Max(65535)
|
|
APP_PORT = 3000;
|
|
|
|
@IsString()
|
|
@IsNotEmpty()
|
|
APP_URL = 'http://172.20.10.59';
|
|
|
|
// Datenbank
|
|
@IsString()
|
|
@IsNotEmpty()
|
|
DATABASE_URL!: string;
|
|
|
|
@IsString()
|
|
@IsOptional()
|
|
DATABASE_URL_DIRECT?: string;
|
|
|
|
// Redis
|
|
@IsString()
|
|
REDIS_HOST = 'redis';
|
|
|
|
@Type(() => Number)
|
|
@IsNumber()
|
|
REDIS_PORT = 6379;
|
|
|
|
@IsString()
|
|
@IsOptional()
|
|
REDIS_PASSWORD?: string;
|
|
|
|
// JWT
|
|
@IsString()
|
|
@IsNotEmpty()
|
|
JWT_PRIVATE_KEY_PATH = '/app/keys/jwt-private.pem';
|
|
|
|
@IsString()
|
|
@IsNotEmpty()
|
|
JWT_PUBLIC_KEY_PATH = '/app/keys/jwt-public.pem';
|
|
|
|
@IsString()
|
|
JWT_ACCESS_TOKEN_EXPIRY = '15m';
|
|
|
|
@IsString()
|
|
JWT_REFRESH_TOKEN_EXPIRY = '7d';
|
|
|
|
@IsString()
|
|
JWT_ISSUER = 'insight-platform';
|
|
|
|
// Bcrypt
|
|
@Type(() => Number)
|
|
@IsNumber()
|
|
@Min(10)
|
|
@Max(14)
|
|
BCRYPT_COST = 12;
|
|
|
|
// Rate Limiting
|
|
@Type(() => Number)
|
|
@IsNumber()
|
|
THROTTLE_TTL = 60000;
|
|
|
|
@Type(() => Number)
|
|
@IsNumber()
|
|
THROTTLE_LIMIT = 200;
|
|
|
|
// Microsoft Entra ID (Azure AD) SSO - optional
|
|
@IsOptional()
|
|
@IsString()
|
|
AZURE_TENANT_ID?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
AZURE_CLIENT_ID?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
AZURE_CLIENT_SECRET?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
AZURE_REDIRECT_URI?: string;
|
|
}
|
|
|
|
export function validateConfig(
|
|
config: Record<string, unknown>,
|
|
): EnvironmentVariables {
|
|
const validatedConfig = plainToInstance(EnvironmentVariables, config, {
|
|
enableImplicitConversion: true,
|
|
});
|
|
const errors = validateSync(validatedConfig, {
|
|
skipMissingProperties: false,
|
|
});
|
|
|
|
if (errors.length > 0) {
|
|
throw new Error(`Config validation error: ${errors.toString()}`);
|
|
}
|
|
return validatedConfig;
|
|
}
|