# Code coverage report for application/services/JwtService.js

# All files / application/services JwtService.js

0% Statements 0/29
0% Branches 0/20
0% Functions 0/8
0% Lines 0/29

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115

     const jwt = require('jsonwebtoken');

    /**
     * JWT Service
     * Handles JWT token generation, verification, and cookie management
     */
    class JwtService {
      constructor() {
        this.secret = process.env.JWT_SECRET || 'default-secret-change-me';
        this.expiresIn = process.env.JWT_EXPIRES_IN || '1h';
        this.cookieName = 'auth_token';
      }

      /**
       * Generate JWT token
       * @param {Object} payload - { userId, email }
       * @returns {string} JWT token
       */
      generateToken(payload) {
        return jwt.sign(payload, this.secret, { expiresIn: this.expiresIn });
      }

      /**
       * Verify JWT token
       * @param {string} token - JWT token
       * @returns {Object} Decoded payload
       */
      verifyToken(token) {
        try {
          return jwt.verify(token, this.secret);
        } catch (error) {
          throw new Error('Invalid or expired token');
        }
      }

      /**
       * Extract token from Authorization header (Bearer token)
       * @param {string} authHeader - Authorization header value
       * @returns {string|null} Token or null
       */
      extractTokenFromHeader(authHeader) {
        if (!authHeader) {
          return null;
        }

        const parts = authHeader.split(' ');

        if (parts.length !== 2 || parts[0] !== 'Bearer') {
          return null;
        }

        return parts[1];
      }

      /**
       * Extract token from cookies
       * @param {Object} cookies - Request cookies object
       * @returns {string|null} Token or null
       */
      extractTokenFromCookies(cookies) {
        if (!cookies || !cookies[this.cookieName]) {
          return null;
        }

        return cookies[this.cookieName];
      }

      /**
       * Get cookie options for setting JWT cookie
       * @returns {Object} Cookie options
       */
      getCookieOptions() {
        const isProduction = process.env.NODE_ENV === 'production';

        return {
          httpOnly: true,        // Prevents XSS attacks
          secure: isProduction,  // HTTPS only in production
          sameSite: 'strict',    // CSRF protection
          maxAge: this._getMaxAge(),
          path: '/'
        };
      }

      /**
       * Get cookie max age in milliseconds
       * @private
       * @returns {number}
       */
      _getMaxAge() {
        // Parse JWT_EXPIRES_IN (e.g., "1h", "7d")
        const expiresIn = this.expiresIn;

        if (expiresIn.endsWith('h')) {
          return parseInt(expiresIn) * 60 * 60 * 1000;
        } else if (expiresIn.endsWith('d')) {
          return parseInt(expiresIn) * 24 * 60 * 60 * 1000;
        } else if (expiresIn.endsWith('m')) {
          return parseInt(expiresIn) * 60 * 1000;
        }

        // Default: 1 hour
        return 60 * 60 * 1000;
      }

      /**
       * Get cookie name
       * @returns {string}
       */
      getCookieName() {
        return this.cookieName;
      }
    }

    module.exports = JwtService;