Implementing Authentication and Authorization Mechanisms
Prompt Template
"Fynix, I need to implement authentication and authorization in my [language/framework] application. Specifically:
- [Describe the authentication requirements]
- [Describe the authorization requirements]
Please provide the necessary code, including any middleware, route handlers, and configurations. Ensure the code is ready to run and includes all necessary imports.“
Scenario
You are building a Node.js RESTful API using Express.js and need to implement user authentication and authorization. Users should be able to:
- Register with a username and password.
- Log in to receive a JWT for authentication.
- Access protected routes only if they provide a valid JWT.
- Implement authorization checks to allow only certain users to access specific routes based on their roles.
Project Structure
auth-example/
├── app.js
├── package.json
├── routes/
│ ├── auth.js
│ └── protected.js
└── users.js
Prompt to Use in Fynix
"Fynix, I need to implement authentication and authorization in my Node.js Express application. Specifically:
-
User Registration and Login:
- Create routes for user registration (
/register
) and login (/login
) in routes/auth.js
. - Use bcrypt to hash passwords before storing them.
- Upon successful login, generate a JWT using jsonwebtoken and send it to the client.
- Create routes for user registration (
-
Protecting Routes with JWT:
- Create a middleware function authenticateToken in app.js to verify JWTs.
- Apply this middleware to protected routes defined in
routes/protected.js
.
-
Authorization Based on User Roles:
- Include a role property (e.g., 'admin', 'user') in the JWT payload.
- In
routes/protected.js
, create a route that only allows access to users with the 'admin' role.
Please provide the necessary code for app.js, routes/auth.js
, routes/protected.js
, and any other files required. Include all necessary imports and ensure the code can be run directly.“
Expected Output from Fynix
package.json
Dependencies
First, ensure the necessary packages are installed:
npm init -y
npm install express jsonwebtoken bcrypt body-parser
// app.js
const express = require('express');
const bodyParser = require('body-parser');
const authRoutes = require('./routes/auth');
const protectedRoutes = require('./routes/protected');
const app = express();
const PORT = 3000;
// Middleware to parse JSON bodies
app.use(bodyParser.json());
// Users data (in-memory for simplicity)
const users = require('./users');
// Middleware to authenticate JWT tokens
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) return res.sendStatus(401); // Unauthorized
const SECRET_KEY = 'your-secret-key'; // Use environment variables in production
require('jsonwebtoken').verify(token, SECRET_KEY, (err, user) => {
if (err) return res.sendStatus(403); // Forbidden
req.user = user;
next();
});
}
app.use('/auth', authRoutes);
app.use('/protected', authenticateToken, protectedRoutes);
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
// users.js
// In-memory user storage
const users = [];
module.exports = users;
// routes/auth.js
const express = require('express');
const router = express.Router();
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const users = require('../users');
const SECRET_KEY = 'your-secret-key'; // Use environment variables in production
// Register Route
router.post('/register', async (req, res) => {
try {
const { username, password, role } = req.body;
// Check if user already exists
if (users.find((user) => user.username === username)) {
return res.status(400).json({ message: 'User already exists' });
}
// Hash the password
const hashedPassword = await bcrypt.hash(password, 10);
// Store user
users.push({ username, password: hashedPassword, role });
res.status(201).json({ message: 'User registered successfully' });
} catch (error) {
res.status(500).json({ message: 'Internal server error' });
}
});
// Login Route
router.post('/login', async (req, res) => {
try {
const { username, password } = req.body;
// Find user
const user = users.find((user) => user.username === username);
if (!user) return res.status(400).json({ message: 'Cannot find user' });
// Compare password
if (await bcrypt.compare(password, user.password)) {
// Generate JWT
const accessToken = jwt.sign(
{ username: user.username, role: user.role },
SECRET_KEY
);
res.json({ accessToken });
} else {
res.status(401).json({ message: 'Password incorrect' });
}
} catch (error) {
res.status(500).json({ message: 'Internal server error' });
}
});
module.exports = router;
// routes/protected.js
const express = require('express');
const router = express.Router();
// Middleware to authorize based on user role
function authorizeRoles(roles) {
return (req, res, next) => {
if (!roles.includes(req.user.role)) {
return res.sendStatus(403); // Forbidden
}
next();
};
}
// Protected route accessible to any authenticated user
router.get('/dashboard', (req, res) => {
res.json({ message: `Hello, ${req.user.username}! Welcome to your dashboard.` });
});
// Protected route accessible only to admin users
router.get('/admin', authorizeRoles(['admin']), (req, res) => {
res.json({ message: `Hello, Admin ${req.user.username}!` });
});
module.exports = router;
Instructions to Run and See Output
-
Set Up the Project
- Create a new directory for the project and navigate into it:
mkdir auth-examplecd auth-example
- Initialize a new Node.js project and install dependencies:
npm init -y
npm install express jsonwebtoken bcrypt body-parser
-
Create the Project Structure
- Create the necessary directories and files:
mkdir routestouch app.js routes/auth.js routes/protected.js users.js
-
Copy the Code
- Copy and paste the provided code snippets into their respective files.
-
Run the Application
- Start the server:
node app.js
- You should see:
Server running on http://localhost:3000
-
Test the Authentication Flow
- Use a tool like Postman or curl to interact with the API.
Register a New User
curl -X POST http://localhost:3000/auth/register \
-H "Content-Type: application/json" \
-d '{"username": "john", "password": "password123", "role": "admin"}'
- Expected Response:
{
"message": "User registered successfully"
}
Log In to Receive a JWT
curl -X POST http://localhost:3000/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "john", "password": "password123"}'
- Expected Response (will include a JWT):
{
"accessToken": "your_jwt_token_here"
}
Access Protected Route (/protected/dashboard)
curl http://localhost:3000/protected/dashboard \
-H "Authorization: Bearer your_jwt_token_here"
- Expected Response:
{
"message": "Hello, john! Welcome to your dashboard."
}
Access Admin Route (/protected/admin)
curl http://localhost:3000/protected/admin \
-H "Authorization: Bearer your_jwt_token_here"
- Expected Response:
{
"message": "Hello, Admin john!"
}
-
Test Unauthorized Access
- Try accessing the protected route without a token:
curl http://localhost:3000/protected/dashboard
- Expected Response:
Unauthorized
Note: Replace 'your-secret-key' with a secure key, preferably stored in an environment variable, when implementing in a real application.