Skip to content

api-authentication

Vue d'ensemble

Le service api-authentication est le point d'entrée principal de la plateforme Roomee. Il gère l'authentification, l'autorisation et la gestion des utilisateurs.

Deux Versions Coexistantes

Le projet contient actuellement deux versions du service d'authentification :

  • api-authentication (moderne) - TypeScript, architecture modulaire
  • api-auth-legacy - JavaScript, structure legacy en cours de migration

Les deux services fonctionnent en parallèle pendant la période de transition.

VersionPortStackStatus
Moderne3000TypeScript, Modules✅ Actif
Legacy3005JavaScript, Flat Structure🔄 En migration

Architecture Comparée

Service Moderne (TypeScript)

mermaid
graph TB
    CLIENT[Client Web/Mobile]

    subgraph "api-authentication (Moderne - TS)"
        ROUTES[Routes Express]

        subgraph "Modules"
            AUTH_MOD[Module Auth]
            USER_MOD[Module User]
            PASS_MOD[Module Password]
        end

        subgraph "Services"
            AUTH_SVC[AuthService]
            USER_SVC[UserService]
            TOKEN_SVC[TokenService]
        end

        ROUTES --> AUTH_MOD
        AUTH_MOD --> AUTH_SVC
        AUTH_SVC --> TOKEN_SVC
    end

    CLIENT --> ROUTES

Service Legacy (JavaScript)

mermaid
graph TB
    CLIENT2[Client Web/Mobile]

    subgraph "api-auth-legacy (JS)"
        ROUTES2[Routes]

        subgraph "Controllers"
            AUTH_CTRL[AuthController<br/>11 méthodes]
            USER_CTRL[UserController<br/>14 méthodes]
        end

        subgraph "Repositories"
            AUTH_REPO[AuthRepository]
            USER_REPO[UserRepository]
            NOTIF_REPO[NotificationsRepository]
        end

        ROUTES2 --> AUTH_CTRL
        ROUTES2 --> USER_CTRL
        AUTH_CTRL --> AUTH_REPO
        USER_CTRL --> USER_REPO
    end

    CLIENT2 --> ROUTES2

Structure des Projets

Service Moderne (TypeScript)

api-authentication/
├── src/
│   ├── app.ts                      # Configuration Express
│   ├── server.ts                   # Point d'entrée
│   ├── modules/
│   │   └── auth/
│   │       ├── controllers/        # Controllers (5)
│   │       ├── services/           # Business logic
│   │       ├── routes/             # Routes Express
│   │       ├── types/              # Interfaces TypeScript
│   │       └── validators/         # Zod schemas
│   ├── config/
│   ├── prisma-client/
│   └── middleware/
├── prisma/
│   └── schema.prisma
└── __tests/

Service Legacy (JavaScript)

api-auth-legacy/
├── controllers/
│   ├── AuthController.js       # 11 méthodes auth
│   └── UserController.js       # 14 méthodes user
├── repository/
│   ├── AuthRepository.js       # Tokens, sessions
│   ├── UserRepository.js       # CRUD users
│   ├── NotificationsRepository.js
│   └── EmailRepository.js
├── routes/
│   ├── auth.routes.js         # 10 endpoints
│   ├── user.routes.js         # 11 endpoints
│   └── docs.routes.js
├── middlewares/
│   ├── auth.js                # Legacy JWT middleware
│   ├── error.js
│   └── rateLimiter.js
├── utils/
│   ├── jwt.js                 # JWT generation (legacy)
│   ├── encryption.js          # bcrypt + AES
│   └── hashToken.js
├── amqp/                      # Communication AMQP
├── socket/                    # Socket.IO
├── gRPC/                      # gRPC (non utilisé)
├── config/
│   ├── config.js              # Infisical integration
│   └── logger.js              # Winston
├── prisma/
│   └── schema.prisma
└── app.js

Modèles de Données

Modèles Communs

User

prisma
model User {
  id                    String                      @id @default(auto()) @map("_id") @db.ObjectId
  email                 String                      @unique
  password              String

  // Flags (spécifiques au Legacy)
  isTmpPassword         Boolean                     @default(false)     // Mot de passe temporaire
  isFirstLogin          Boolean                     @default(false)     // Premier login
  isForced              Boolean                     @default(false)     // Force changement MDP

  // Status
  isActive              Boolean                     @default(true)
  isAdmin               Boolean                     @default(false)
  emailVerified         Boolean                     @default(false)

  // Dates
  createdAt             DateTime                    @default(now())
  updatedAt             DateTime                    @updatedAt
  lastLoginAt           DateTime?

  // Relations
  refreshTokens         RefreshToken[]
  sessions              UserSession[]
  invitationsSent       InvitationToken[]           // Moderne uniquement
  passwordRequests      RequestCreatePassword[]
  ecosystemCredentials  EcosystemCredentials[]      // Moderne uniquement
}

Champs Legacy importants :

  • isTmpPassword : Indique un mot de passe temporaire (invitation/admin reset)
  • isFirstLogin : Détecte la première connexion
  • isForced : Force le changement de mot de passe à la prochaine connexion

RefreshToken

prisma
model RefreshToken {
  id          String   @id @default(auto()) @map("_id") @db.ObjectId

  // Moderne
  token       String   @unique                         // Token JWT en clair
  isRevoked   Boolean  @default(false)

  // Legacy
  hashedToken String                                   // Token hashé (SHA256)
  revoked     Boolean  @default(false)                 // Alias de isRevoked

  userId      String   @db.ObjectId
  User        User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  expiresAt   DateTime
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@index([userId])
  @@index([token])
  @@index([hashedToken])
}

UserSession

prisma
model UserSession {
  id          String   @id @default(auto()) @map("_id") @db.ObjectId

  // Moderne
  userId      String?  @db.ObjectId
  user        User?    @relation(fields: [userId], references: [id], onDelete: Cascade)
  deviceInfo  Json?    // { userAgent, ip, device, os }
  expiresAt   DateTime?

  // Legacy
  memberId    String                                   // ID du membre (api-staff-member)
  userAgent   String
  ip          String
  appType     String                                   // "mobile" ou "dashboard"
  timestamp   DateTime @default(now())

  // Commun
  isActive    Boolean  @default(true)
  lastActivity DateTime @default(now())
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@index([userId])
  @@index([memberId])
  @@index([isActive])
}

RequestCreatePassword (Legacy)

prisma
model RequestCreatePassword {
  id          String   @id @default(auto()) @map("_id") @db.ObjectId
  email       String
  hashedToken String                                   // Token JWT hashé
  couponCode  String                                   // Code à 6 chiffres

  // Moderne (optionnel)
  userId      String?  @db.ObjectId
  user        User?    @relation(fields: [userId], references: [id])
  token       String?  @unique
  isUsed      Boolean? @default(false)
  expiresAt   DateTime?

  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@index([email])
  @@index([hashedToken])
  @@index([couponCode])
  @@index([token])
}

Usage Legacy : Workflow de reset avec code à 6 chiffres

Modèles Spécifiques Moderne

InvitationToken

prisma
model InvitationToken {
  id          String   @id @default(auto()) @map("_id") @db.ObjectId
  invitedBy   String   @db.ObjectId
  email       String
  token       String   @unique
  role        String   // 'admin', 'member', 'viewer'
  workspaceId String?
  expiresAt   DateTime
  isUsed      Boolean  @default(false)
  createdAt   DateTime @default(now())

  inviter     User     @relation(fields: [invitedBy], references: [id])

  @@index([email])
  @@index([token])
}

EcosystemCredentials

prisma
model EcosystemCredentials {
  id           String   @id @default(auto()) @map("_id") @db.ObjectId
  userId       String   @db.ObjectId
  ecosystemId  String
  apiKey       String   @unique
  apiSecret    String   // Encrypted
  permissions  String[]
  isActive     Boolean  @default(true)
  createdAt    DateTime @default(now())
  expiresAt    DateTime?

  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([userId])
  @@index([ecosystemId])
  @@index([apiKey])
}

Modèles Spécifiques Legacy

Administrator

prisma
model Administrator {
  id        String   @id @default(auto()) @map("_id") @db.ObjectId
  email     String   @unique
  password  String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

Usage : Compte super-administrateur système (distinct des users)

UserLog

prisma
model UserLog {
  id        String   @id @default(auto()) @map("_id") @db.ObjectId
  timestamp DateTime @default(now())
  userId    String?  @db.ObjectId
  level     String   // error, warn, info, debug
  message   String
  meta      Json?
}

Usage : Logs applicatifs stockés en base (en plus de Winston)


Routes API - Comparaison

Routes Communes

EndpointModerne (TS)Legacy (JS)Différences
POST /auth/registerLegacy : registerTemp avec token membre
POST /auth/login/auth/login/:typeLegacy : type mobile/dashboard
POST /auth/refreshToken/auth/refreshNoms différents
POST /auth/logout-Moderne uniquement
POST /auth/verify-email-Moderne uniquement
GET /users/me/user/profilePaths différents
PATCH /users/me-Moderne uniquement
DELETE /users/me-Moderne uniquement
POST /password/forgot/user/sentreset/emailPaths différents
POST /password/reset/user/change/PasswordPaths différents
POST /password/change/user/changePasswordModerne : nécessite auth

Routes Spécifiques Legacy

POST /auth/loginAsAdmin

Connexion en tant qu'administrateur système.

Request :

json
{
  "email": "admin@roomee.io",
  "password": "AdminPassword"
}

Response :

json
{
  "accessToken": "eyJhbGciOiJI...",
  "refreshToken": "8f7d6c5b4a3...",
  "admin": {
    "id": "65f1234567890abcdef12345",
    "email": "admin@roomee.io"
  }
}

POST /auth/invitation

Création ou mise à jour d'un compte avec mot de passe temporaire.

Request :

json
{
  "email": "newuser@hotel.com",
  "password": "TempP@ss123",
  "memberId": "65f9876543210fedcba98765"
}

Response :

json
{
  "success": true,
  "user": {
    "id": "65f1234567890abcdef12345",
    "email": "newuser@hotel.com",
    "isTmpPassword": true,
    "isFirstLogin": true
  }
}

Logique :

  1. Création ou mise à jour du compte User
  2. Flag isTmpPassword: true
  3. L'utilisateur doit changer son mot de passe lors de la première connexion

POST /auth/set-login-data

Configuration des données de connexion (flags système).

Request :

json
{
  "userId": "65f1234567890abcdef12345",
  "isTmpPassword": false,
  "isFirstLogin": false,
  "isForced": false
}

DELETE /auth/delete/:email

Suppression d'un utilisateur par email (admin).


PUT /auth/change_mail

Changement d'email utilisateur.

Request :

json
{
  "oldEmail": "old@example.com",
  "newEmail": "new@example.com"
}

POST /auth/revokeRefreshTokens

Révocation de tous les refresh tokens d'un utilisateur.

Request :

json
{
  "userId": "65f1234567890abcdef12345"
}

POST /user/check/reset/code

Vérification du code de reset à 6 chiffres.

Request :

json
{
  "email": "user@example.com",
  "code": "123456"
}

Response :

json
{
  "success": true,
  "data": {
    "hashedToken": "...",
    "couponCode": "123456"
  }
}

POST /user/change/Password/by/admin

Reset de mot de passe par un administrateur.

Request :

json
{
  "email": "user@example.com"
}

Response :

json
{
  "success": true,
  "temporaryPassword": "TempP@ss789",
  "message": "Temporary password sent by email"
}

Logique :

  1. Génération d'un mot de passe temporaire aléatoire
  2. Hash et stockage avec isTmpPassword: true
  3. Envoi d'email avec le mot de passe temporaire

PUT /user/changePassword

Changement de mot de passe dans l'application.

Headers :

Authorization: Bearer eyJhbGciOiJI...

Request :

json
{
  "oldPassword": "OldP@ss123",
  "newPassword": "NewP@ss456"
}

Response :

json
{
  "success": true,
  "msg": "password updated!",
  "user": {
    "isTmpPassword": false,
    "isFirstLogin": false,
    "isForced": false
  }
}

POST /user/reset_password/request

Demande de réinitialisation avec génération de code.

Request :

json
{
  "email": "user@example.com"
}

Response :

json
{
  "email": "user@example.com",
  "generatedcode": "123456",
  "tokenFrontRoute": "https://app.roomee.io/reset-password?token=..."
}

Logique :

  1. Génération d'un code à 6 chiffres aléatoire
  2. Génération d'un token JWT chiffré
  3. Stockage dans RequestCreatePassword
  4. Envoi d'email avec code et lien
  5. Expiration : 24h

POST /user/reset_password/request/check

Vérification de la demande de reset avec code.


DELETE /user/ecosystem/delete

Suppression complète d'un écosystème (transaction).

Request :

json
{
  "ecosystemId": "65f1111111111111111111111"
}

Logique :

  1. Suppression de tous les utilisateurs de l'écosystème
  2. Révocation de tous les tokens
  3. Suppression des sessions
  4. Transaction Prisma pour garantir l'atomicité

DELETE /user/tokens/:userId

Révocation de tous les tokens d'un user par ID.


POST /user/tokens/revoke

Révocation de tous les tokens d'un user par email.


GET /user/profileAsAdmin

Récupération du profil administrateur.


Routes Spécifiques Moderne

POST /invitations/send

Envoyer une invitation structurée.

POST /invitations/accept

Accepter une invitation avec création de compte.

GET /invitations

Lister les invitations envoyées.

POST /ecosystem/credentials

Générer des credentials API pour intégrations.

GET /ecosystem/credentials/:ecosystemId

Lister les credentials d'un écosystème.

DELETE /ecosystem/credentials/:id

Révoquer des credentials.


Workflow de Reset Password

Version Legacy (Code à 6 Chiffres)

mermaid
sequenceDiagram
    participant User
    participant API as api-auth-legacy
    participant Email as api-notification
    participant DB as MongoDB

    User->>API: POST /user/sentreset/email
    API->>API: Generate 6-digit code
    API->>API: Generate JWT token
    API->>DB: Store RequestCreatePassword
    API->>Email: Send email with code + link
    Email-->>User: Email reçu

    User->>API: POST /user/check/reset/code
    Note over API: Validate code + token
    API-->>User: { hashedToken, couponCode }

    User->>API: PUT /user/change/Password
    API->>DB: Update password
    API->>DB: Set isTmpPassword=false
    API-->>User: Success

Avantages :

  • Code court facile à saisir manuellement
  • Double vérification (code + token JWT)
  • Expiration 24h

Version Moderne (Token uniquement)

mermaid
sequenceDiagram
    participant User
    participant API as api-authentication
    participant Email as Service Email
    participant DB as MongoDB

    User->>API: POST /password/forgot
    API->>DB: Create RequestCreatePassword
    API->>API: Generate unique token
    API->>Email: Send email with link
    Email-->>User: Email reçu

    User->>API: POST /password/reset
    Note over API: Validate token (not used, not expired)
    API->>DB: Update password
    API->>DB: Mark token as used
    API->>DB: Revoke all refresh tokens
    API-->>User: Success

Avantages :

  • Plus simple (pas de code à saisir)
  • Expiration 1h (plus court = plus sécurisé)

Génération de Tokens JWT

Service Moderne (@roomee/shared)

typescript
import { authMiddleware } from '@roomee/shared'

authMiddleware.initialize({
  jwtAccessSecret: process.env.JWT_ACCESS_SECRET
})

// Génération de token
const token = authMiddleware.generateToken({
  userId: user.id,
  email: user.email,
  isAdmin: user.isAdmin,
  workspaceId: memberData.workspaceId,
  roles: memberData.roles,
  permissions: memberData.permissions
})

// Token chiffré avec AES-256-GCM
// Format : {encryptedText}.{iv}.{tag}

Service Legacy (utils/jwt.js + @roomee/shared)

javascript
// Payload complet Legacy
const payload = {
  userId: user.id,
  email: user.email,
  isAdmin: user.isAdmin || false,

  // Données membre (api-staff-member)
  ecosystemId: memberData.hotelId,
  hotelId: memberData.hotelId,
  memberId: memberData.id,
  chatApiKey: memberData.sendBirdAccessToken,
  firstname: memberData.firstname,
  lastname: memberData.lastname,
  picture: memberData.picture,

  // Workspace
  workspaceId: memberData.workspaces[0]?.id,
  workspace_id: memberData.workspaces[0]?.id,

  // RBAC
  roles: ['user', 'admin', 'superadmin', 'member'],
  permissions: ['member.management', 'page.management'],

  // Flags
  asAdminRole: false
}

// Génération via @roomee/shared
const accessToken = authMiddleware.generateToken(payload)

// Refresh token
const refreshToken = authMiddleware.generateRefreshToken({
  userId: user.id,
  jti: uuidv4() // JWT ID unique
})

Différence majeure : Le legacy inclut beaucoup plus de données membre dans le payload JWT


Expiration des Tokens

TokenModerneLegacyRecommandation
Access Token15 min2400h (100 jours) ⚠️15-60 min
Refresh Token7 jours7 jours7-30 jours
Reset Token1h24h1-24h
Invitation Token7 jours4h (create password)7 jours

Problème de Sécurité Legacy

L'access token legacy expire dans 2400h (100 jours), ce qui est extrêmement long et pose un risque de sécurité majeur. Il devrait être réduit à 15-60 minutes maximum.


Communication AMQP

Service Legacy

Configuration :

javascript
{
  rabbitMQUrl: config.amqpGatewayUrl,
  exchangeName: config.amqpExchangeName,
  queueName: 'authentication_queue',
  routingKeyBase: 'roomee.authentication'
}

Routing Keys :

  • roomee.authentication.* - Événements internes
  • roomee.notification.socket - Notifications Socket.IO
  • roomee.webhook.report-error - Rapports d'erreurs

Mode : Émission uniquement (pas de consommation)

Service Moderne

Configuration similaire avec routing keys modernes.


Intégration avec api-staff-member

Les deux services communiquent avec api-staff-member pour :

Récupération de Profil Membre

javascript
// Legacy
GET /members/get/light/:email

// Moderne
GET /members/get/with/:email

Response :

json
{
  "id": "65f9876543210fedcba98765",
  "firstname": "John",
  "lastname": "Doe",
  "picture": "https://...",
  "hotelId": "65f1111111111111111111111",
  "workspaces": [
    {
      "id": "65f2222222222222222222222",
      "name": "Grand Hotel Paris",
      "role": "admin"
    }
  ],
  "roles": ["admin", "member"],
  "permissions": ["manage_members", "create_content"],
  "sendBirdAccessToken": "sendbird-token-abc123",
  "deleted_at": null
}

Marquage Registered (Legacy)

javascript
PUT /members/registered/update

Body: {
  memberId: "65f9876543210fedcba98765"
}

Marque le membre comme "registered" dans api-staff-member lors de la première connexion.

Création de Session (Legacy)

javascript
POST /sessions

Body: {
  memberId: "65f9876543210fedcba98765",
  userAgent: "Mozilla/5.0...",
  ip: "192.168.1.1",
  appType: "mobile" | "dashboard",
  isActive: true
}

Sécurité

Encryption AES-256-GCM (@roomee/shared)

typescript
import { encryptionService } from '@roomee/shared'

encryptionService.initialize(process.env.PASSWORD_ENCRYPTION_KEY)

// Encryption
const encrypted = await encryptionService.encrypt(plainText)
// Format : {encryptedText}.{iv}.{tag}

// Décryption
const decrypted = await encryptionService.decrypt(encrypted)

// Comparaison sécurisée (passwords)
const isValid = await encryptionService.compare(plain, encrypted)

Hashing bcrypt (Passwords)

javascript
import bcrypt from 'bcrypt'

// Hash
const hashedPassword = await bcrypt.hash(plainPassword, 10)

// Vérification
const isMatch = await bcrypt.compare(plainPassword, hashedPassword)

Hashing SHA256 (Tokens Legacy)

javascript
// utils/hashToken.js
import crypto from 'crypto'

function hashToken(token) {
  return crypto.createHash('sha256').update(token).digest('hex')
}

Usage : Les refresh tokens legacy sont hashés avant stockage en base.


Codes de Messages (Legacy)

Le service legacy utilise des codes de messages standardisés :

CodeDescription
NO_MSGPas de message
MSG_600Email et mot de passe requis
MSG_601Identifiants invalides
MSG_602Membre introuvable
MSG_603Pas d'accès mobile
MSG_604Pas d'accès web
MSG_605Code de reset envoyé
MSG_606Échec reset mot de passe
MSG_620Mot de passe modifié avec succès
MSG_621Erreur mise à jour mot de passe
MSG_622Ancien mot de passe incorrect
MSG_623Utilisateur inexistant
MSG_624Session active en cours

Usage :

javascript
res.status(401).json({
  msg: ResponseMessage.MSG_601, // "Identifiants invalides"
  success: false
})

Logging

Service Moderne

Winston logger standard avec console + fichiers.

Service Legacy

Winston logger avancé avec multiples transports :

javascript
const transports = [
  new winston.transports.Console(),
  new winston.transports.DailyRotateFile({
    filename: 'logs/error-%DATE%.log',
    level: 'error',
    datePattern: 'YYYY-MM-DD',
    maxSize: '20m',
    maxFiles: '14d'
  }),
  new winston.transports.DailyRotateFile({
    filename: 'logs/combined-%DATE%.log',
    datePattern: 'YYYY-MM-DD',
    maxSize: '20m',
    maxFiles: '14d'
  }),
  new winston.transports.MongoDB({
    db: DATABASE_URL,
    collection: 'UserLog',
    level: 'info'
  }),
  new winston.transports.Http({
    host: 'discord-webhook-url',
    level: 'error' // Alertes critiques vers Discord
  })
]

Configuration

Variables Communes

bash
# Server
PORT=3000  # Moderne
PORT=3005  # Legacy
NODE_ENV=development|production|staging

# Database
DATABASE_URL=mongodb://localhost:27017/roomee_authentication

# JWT
JWT_ACCESS_SECRET=your-jwt-secret
JWT_REFRESH_SECRET=your-refresh-secret

# Encryption
PASSWORD_ENCRYPTION_KEY=your-32-byte-encryption-key

# API URLs
MEMBER_API_URL=http://localhost:3001
NOTIFICATION_API_URL=http://localhost:3005  # Legacy uniquement

# Frontend
FRONT_BASE_URL=http://localhost:3000
FRONT_RESET_PASSWORD_SUFFIX=/reset-password?token=

# AMQP
AMQP_GATEWAY_URL=amqp://localhost:5672
AMQP_EXCHANGE_NAME=roomee_events
AMQP_QUEUE_NAME=authentication_queue
AMQP_ROUTING_KEY_BASE=roomee.authentication

Variables Spécifiques Legacy

bash
# Infisical Secrets Management
INFISICAL_SITE_URL=https://app.infisical.com
INFISICAL_CLIENT_ID=your-client-id
INFISICAL_CLIENT_SECRET=your-client-secret
INFISICAL_PROJECT_ID=your-project-id

# Email (via api-notification)
API_NOTIFICATION_SUFFIX=:3005

Migration en Cours

Stratégie de Migration

mermaid
graph LR
    LEGACY[Legacy JS] -->|Phase 1| COEXIST[Coexistence]
    COEXIST -->|Phase 2| MODERNE[Moderne TS]

    COEXIST -->|Migration| DATA[Migration Données]
    COEXIST -->|Refactor| ROUTES[Standardisation Routes]
    COEXIST -->|Update| CLIENTS[Mise à jour Clients]

Phase Actuelle : Coexistence

  • ✅ Les deux services sont opérationnels
  • ✅ Service moderne implémente les fonctionnalités de base
  • 🔄 Service legacy continue d'être utilisé en production
  • 🔄 Migration progressive des clients vers le service moderne

Différences Clés

AspectModerneLegacy
LangageTypeScriptJavaScript
ArchitectureModulaire (modules/)Flat (controllers/)
JWT100% @roomee/sharedMix custom + @roomee/shared
TokensEn clair en baseHashés (SHA256)
Reset PasswordToken uniquementToken + Code 6 chiffres
InvitationSystème structuréEndpoint /auth/invitation
Access Token TTL15 min2400h ⚠️
ValidationZod schemasJoi schemas
ConfigurationENV directInfisical integration
LogsConsole + filesMulti-transport (MongoDB, Discord)

Recommandations de Migration

  1. Priorité 1 : Réduire TTL access token legacy de 2400h à 15-60 min
  2. Priorité 2 : Migrer tous les clients vers endpoints modernes
  3. Priorité 3 : Déprécier progressivement les routes legacy
  4. Priorité 4 : Migration complète des données
  5. Priorité 5 : Décommissionnement du service legacy

Tests

Service Moderne

typescript
// __tests__/auth.service.test.ts
describe('AuthService', () => {
  it('should create a new user', async () => {
    const user = await authService.register({
      email: 'test@example.com',
      password: 'SecureP@ss123'
    })

    expect(user).toHaveProperty('id')
    expect(user.isTmpPassword).toBe(false)
  })
})

Service Legacy

Tests à implémenter (actuellement manquants).


Commandes

Service Moderne

bash
npm run dev              # Développement
npm run build            # Build TypeScript
npm run test             # Tests Jest
npm run prisma:generate  # Génération client Prisma

Service Legacy

bash
npm run dev              # Développement avec nodemon
npm run swagger-autogen  # Génération Swagger
npm run prisma:migrate   # Migration Prisma
npm run bot              # Bot de logs Discord

Documentation API

Service Moderne

À venir (Swagger à implémenter)

Service Legacy

Swagger UI : http://localhost:3005/docs/

  • Disponible en développement uniquement
  • Auto-généré avec npm run swagger-autogen
  • Fichier : docs/authenticate-swagger.json

Bonnes Pratiques

1. Toujours utiliser @roomee/shared pour JWT

typescript
// ✅ BON
import { authMiddleware } from '@roomee/shared'
const token = authMiddleware.generateToken(payload)

// ❌ ÉVITER (legacy custom JWT)
import { generateAccessToken } from './utils/jwt'

2. Valider les entrées

typescript
// Moderne : Zod
const schema = z.object({
  email: z.string().email(),
  password: z.string().min(8)
})

// Legacy : Joi
const schema = Joi.object({
  email: Joi.string().email().required(),
  password: Joi.string().min(8).required()
})

3. Logger les actions importantes

javascript
logger.info('User logged in', {
  userId: user.id,
  email: user.email,
  ip: req.ip,
  appType: req.params.type
})

4. Gérer les flags correctement (Legacy)

javascript
// Lors de la première connexion
if (user.isTmpPassword || user.isFirstLogin) {
  // Force changement de mot de passe
  return {
    ...tokens,
    isTmpPassword: user.isTmpPassword,
    isFirstLogin: user.isFirstLogin,
    requirePasswordChange: true
  }
}

Limitations et Améliorations

Limitations Actuelles

Service Moderne :

  • ❌ Pas d'OAuth (Google, GitHub)
  • ❌ Pas de 2FA
  • ❌ Pas de rate limiting distribué (Redis)
  • ❌ Swagger documentation à créer

Service Legacy :

  • ⚠️ Access token TTL trop long (2400h)
  • ❌ Pas de tests
  • ❌ Code mort et commenté à nettoyer
  • ❌ gRPC configuré mais non utilisé
  • ❌ Socket.IO présent mais non activé

Roadmap

Court Terme :

  • [ ] Réduire TTL access token legacy à 15-60 min
  • [ ] Implémenter tests pour les deux services
  • [ ] Ajouter Swagger au service moderne
  • [ ] Nettoyer code legacy

Moyen Terme :

  • [ ] Migration complète vers service moderne
  • [ ] Implémenter OAuth 2.0
  • [ ] Ajouter 2FA (TOTP)
  • [ ] Cache Redis pour sessions
  • [ ] Décommissionner service legacy

Long Terme :

  • [ ] WebAuthn / Passkeys
  • [ ] Authentification biométrique
  • [ ] SSO pour entreprises
  • [ ] Architecture zero-trust

Résumé

Le projet dispose de deux services d'authentification :

  1. api-authentication (Moderne) : TypeScript, modulaire, en développement actif
  2. api-auth-legacy : JavaScript, flat structure, en production mais en cours de migration

Points clés :

  • Les deux services sont fonctionnels et coexistent
  • Le legacy a plus de fonctionnalités spécifiques (codes 6 chiffres, flags système)
  • Le moderne est plus propre et maintenable
  • Migration progressive en cours vers le service moderne
  • Attention : Access token legacy expire dans 2400h (à corriger en priorité)

Pour les nouveaux développements, utilisez le service moderne (TypeScript) et suivez les patterns @roomee/shared.

Documentation technique Roomee Services