<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: M DISHA SHETTY</title>
    <description>The latest articles on DEV Community by M DISHA SHETTY (@m_disha_shetty).</description>
    <link>https://dev.to/m_disha_shetty</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2912910%2F1451b0a2-1e61-460f-9e39-0fb5d8b27979.png</url>
      <title>DEV Community: M DISHA SHETTY</title>
      <link>https://dev.to/m_disha_shetty</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/m_disha_shetty"/>
    <language>en</language>
    <item>
      <title>Making Your Express.js API Secure: Authentication Middleware &amp; Token Management</title>
      <dc:creator>M DISHA SHETTY</dc:creator>
      <pubDate>Fri, 07 Mar 2025 07:07:14 +0000</pubDate>
      <link>https://dev.to/m_disha_shetty/making-your-expressjs-api-secure-authentication-middleware-token-management-126o</link>
      <guid>https://dev.to/m_disha_shetty/making-your-expressjs-api-secure-authentication-middleware-token-management-126o</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foo3nptqnu5ykow6bp82j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foo3nptqnu5ykow6bp82j.jpg" alt="Image description" width="800" height="425"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://drive.google.com/file/d/1VCnDMv5f1RcKqiIKNlmGPxxupwkqi92d/view?usp=sharing" rel="noopener noreferrer"&gt;Link&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Why Authentication Matters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine leaving your house unlocked—anyone could walk in and take what they want. APIs work the same way. Without proper authentication, attackers can gain access to sensitive data or manipulate your system. JWTs and API keys provide a structured way to ensure only authorized users can use your API securely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Authentication Middleware Works&lt;/strong&gt;&lt;br&gt;
_&lt;br&gt;
Our middleware handles two types of authentication:_&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API Keys&lt;/strong&gt;: If an API key is included in the request, it’s checked against a stored value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JWTs&lt;/strong&gt;: If no API key is found, the system looks for a JWT token in the Authorization header, validates it, and checks the user's permissions.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Here’s the authMiddleware.js in action:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Configs from '../configs/config.js';
import { verifyAccessToken } from '../helpers/tokenManager.js';
import errorHandler from '../helpers/errorHandler.js';

export default function authMiddleware(requiredRoles = []) {
  return async (req, res, next) =&amp;gt; {
    try {
      const authHeader = req.headers.authorization;
      const apiKeyHeader = req.headers['x-api-key'];

      if (apiKeyHeader) {
        if (!Configs?.X_API_KEY_DEV) {
          throw new Error('NOT_FOUND X_API_KEY_DEV is not set in environment');
        }

        if (apiKeyHeader !== Configs?.X_API_KEY_DEV) {
          throw new Error('FORBIDDEN Invalid or missing x-api-key');
        }
        return next();
      }

      if (!authHeader || !authHeader.startsWith('Bearer ')) {
        throw new Error('UNAUTHORIZED Authentication token is missing or malformed.');
      }

      const token = authHeader.replace('Bearer ', '');
      const decoded = await verifyAccessToken(token);

      if (decoded.name === 'TokenExpiredError') {
        throw new Error('UNAUTHORIZED Token expired.');
      }

      if (requiredRoles.length &amp;amp;&amp;amp; !requiredRoles.includes('XAPIKEY')) {
        const hasRole = requiredRoles.some(roleNeeded =&amp;gt;
          decoded.roles?.some(role =&amp;gt; role.permissions?.includes(roleNeeded))
        );
        if (!hasRole) {
          throw new Error('FORBIDDEN You do not have the required permissions.');
        }
      }

      req.user_id = decoded.sub || null;
      return next();
    } catch (err) {
      const error = errorHandler(err);
      return res.status(error.code).json({ message: error.message, keyword: error.keyword });
    }
  };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How JWT Token Management Works&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;JWT tokens contain user details and are signed to ensure their validity. To verify a token, we:&lt;/p&gt;

&lt;p&gt;Decode its header to get the kid (Key ID).&lt;/p&gt;

&lt;p&gt;Fetch the public key from the JWKS endpoint.&lt;/p&gt;

&lt;p&gt;Use the key to validate the token’s signature and confirm its authenticity.&lt;/p&gt;

&lt;p&gt;Here’s how we handle it in tokenManager.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fs from 'fs';
import path from 'path';
import axios from 'axios';
import jwt from 'jsonwebtoken';
import crypto from 'crypto';
import Configs from '../configs/config.js';

const keysDirPath = path.join(__dirname, '../../keys');
const baseUrl = `${Configs.JWKS_URI}?secret=${Configs.JWKS_SECRET}&amp;amp;kid=`;

export async function verifyAccessToken(token) {
  try {
    const decodedHeader = jwt.decode(token, { complete: true }).header;
    let publicKey = checkLocalKeyDirectory(decodedHeader.kid);
    if (!publicKey) {
      publicKey = await fetchAndSaveKey(decodedHeader.kid);
    }

    const verifyOptions = { issuer: Configs.TOKEN_ISSUER, algorithms: ['RS256'] };
    if (Configs.TOKEN_AUDIENCE) {
      verifyOptions.audience = Configs.TOKEN_AUDIENCE;
    }

    return jwt.verify(token, publicKey, verifyOptions);
  } catch (error) {
    throw error;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Best Practices for Secure Authentication&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Keep Secrets Safe: Store API keys and JWT secrets in environment variables.&lt;/p&gt;

&lt;p&gt;Handle Token Expiry: Implement token refresh to prevent expired tokens from causing issues.&lt;/p&gt;

&lt;p&gt;Rate Limit Requests: Prevent API abuse by limiting request frequency per user.&lt;/p&gt;

&lt;p&gt;Monitor Authentication Failures: Log failed login attempts for security analysis.&lt;/p&gt;

&lt;p&gt;Use Role-Based Access Control (RBAC): Assign permissions based on user roles.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Utilizing Worker Threads in Node.js to Efficiently Facilitate the Upload Process of a File into an Amazon S3 Bucket.</title>
      <dc:creator>M DISHA SHETTY</dc:creator>
      <pubDate>Wed, 05 Mar 2025 09:28:04 +0000</pubDate>
      <link>https://dev.to/m_disha_shetty/uploading-a-image-into-s3-bucket-using-worker-threads-in-node-js-2mde</link>
      <guid>https://dev.to/m_disha_shetty/uploading-a-image-into-s3-bucket-using-worker-threads-in-node-js-2mde</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqadys92zm6rdafgftwg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqadys92zm6rdafgftwg.png" alt="Image description" width="800" height="322"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://drive.google.com/file/d/1JGIlaiJNlNNSVm1CqvmqfHaKUdvegryd/view?usp=sharing" rel="noopener noreferrer"&gt;LINK FOR FLOWCHART&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;How to Implement  *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;File Upload Process:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The user will upload the file via /upload endpoint and API immediately returns a response: "File uploaded successfully&lt;br&gt;
The file details (path, job_applicant_id) are added to a queue for processing.&lt;br&gt;
A worker thread picks up the file and uploads it to S3 Bucket.&lt;br&gt;
THe Path is stored in Database as well with the path name&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Fetching the File:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;1.When a user requests the file via and API(fetch/job_applicant_id/filepath) by the path name&lt;/p&gt;

&lt;p&gt;2.The API generates a signed URL for temporary access and returns it&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;IMPLEMENTATION PART:&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. File Upload API&lt;/strong&gt;&lt;br&gt;
Uses multer to handle file uploads.&lt;br&gt;
Adds the file path to a queue for processing.&lt;br&gt;
Responds immediately without waiting for the file to upload.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');
const multer = require('multer');
const threadController = require('./threadController');

const app = express();
const upload = multer({ dest: 'uploads/' });

app.post('/upload', upload.single('file'), (req, res) =&amp;gt; {
    const { job_applicant_id } = req.body;
    const filePath = req.file.path;
    const fileName = req.file.originalname;

    threadController.addToQueue(job_applicant_id, filePath, fileName);
    res.json({ message: 'File uploaded successfully' });
});

app.listen(3000, () =&amp;gt; {
    console.log('Server running on port 3000');
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Worker Thread for Uploading to S3&lt;/strong&gt;&lt;br&gt;
Picks up files from the queue.&lt;br&gt;
Uploads them to S3 under job_applicant_id.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { isMainThread, parentPort, workerData } = require('worker_threads');
const AWS = require('aws-sdk');
const fs = require('fs');

AWS.config.update({
    accessKeyId: 'AWS_ACCESS_KEY',
    secretAccessKey: 'AWS_SECRET_KEY',
    region: 'us-east-1'
});

const s3 = new AWS.S3();

if (!isMainThread) {
    const { job_applicant_id, filePath, fileName } = workerData;
    const fileStream = fs.createReadStream(filePath);

    const params = {
        Bucket: 'my-file-bucket',
        Key: `${job_applicant_id}/${fileName}`,
        Body: fileStream,
        ContentType: 'application/pdf'
    };

    s3.upload(params).promise()
        .then(data =&amp;gt; console.log(`File uploaded: ${data.Location}`))
        .catch(err =&amp;gt; console.error(`Upload failed: ${err.message}`));
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Fetch File API&lt;/strong&gt;&lt;br&gt;
Retrieves a temporary signed URL to access the file.&lt;br&gt;
app.get('/get-file/:job_applicant_id/:file_name', (req, res) =&amp;gt; {&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;` const { job_applicant_id, file_name } = req.params;

    const params = {
        Bucket: 'my-file-bucket',
        Key: `${job_applicant_id}/${file_name}`,
        Expires: 60 * 5 // Link valid for 5 minutes
    };

    const url = s3.getSignedUrl('getObject', params);
    res.json({ url });
});`

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>webdev</category>
      <category>node</category>
      <category>s3</category>
      <category>bucket</category>
    </item>
  </channel>
</rss>
