So when I learning my backend course I implemented JWT for Authentication. Here how i understand this concept and How I implemented them in my project
JWT stands for JSON web Token. This is a compact and self-contained way for securely transmitting information between parties as a JSON object.
In the my context of Express and Node.js, JWTs are often used for authentication and authorization. Here’s how JWT token work in an Express and Node.js environment:
1. User Authentication and Token Creation
- User Login: The user provides their credentials (e.g., username (or email) and password) to login.
- Server verification: The server verifies the credentials (typically against a database).
- Token Generation: Upon successful verification, the server generat a JWT token containing user-specific data(e.g., user ID, role, or other claims). This token is then signed using a secret key or a public/private key pair.
- Token Structure:
- Header: Specifies the type to token (JWT) and the singin algoritham (e.g, HS256)
- Payload: Contains the claims, which can be predefined or custom, like
sub(subject),exp(expiration time), etc. - Signature: A hash of the header and payload combined with the secret key.
- Token Structure:
Example in Node.js using jsonwebtoken package:
//user.model.js
import jwt from "jsonwebtoken";
userSchema.methods.generateAccessToken = function () {
return jwt.sign(
{
_id: this._id,
email: this.email,
username: this.username,
fullName: this.fullName,
},
process.env.ACCESS_TOKEN_SECRET,
{
expiresIn: process.env.ACCESS_TOKEN_EXPIRY,
}
);
};
userSchema.methods.generateRefreshToken = function () {
return jwt.sign(
{
_id: this._id,
},
process.env.REFRESH_TOKEN_SECRET,
{
expiresIn: process.env.REFRESH_TOKEN_EXPIRY,
}
);
};
//user.controller.js
...
const generateAccessAndRefreshTokens = async (userId) => {
try {
const user = await User.findById(userId); // I get Issue becouse of not adding "await"
// console.log("Before User in user contriller - accessToken:")
const accessToken = user.generateAccessToken();
// console.log("User in user contriller - accessToken: ", accessToken)
const refreshToken = user.generateRefreshToken();
// console.log("User in user contriller - refreshToken: ", refreshToken)
user.refreshToken = refreshToken;
await user.save({ validateBeforeSave: false });
return { accessToken, refreshToken };
} catch (error) {
// console.error("Error generating access token: ", error);
throw new ApiError(
500,
"Something went wrong while generation refresh and access token"
);
}
};
...
// in Login controller we call it like this.
const { accessToken, refreshToken } = await generateAccessAndRefreshTokens(
user._id
);
2. Client-Side Storage and Transmission
- Storing the Token: The client (usually a web or mobile application) stores the JWT token. Common storage methods include localStorage, sessionStorage, or cookies.
- Sending the Token: The token is sent with each request to the server, typically in the
Authorizationheader using the Bearer schema:
authorization: Bearer <your_jwt_token>
3. Token Verification
- Token Extraction: The server extracts the token from the incoming request (usually from the headers).
- Token Verification: The server verifies the token using the same secret key or public key that was used to sign it. This process checks the token’s integrity and ensures it hasn’t been tampered with. It also checks if the token has expired or is otherwise invalid.
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
const secretKey = 'your_secret_key';
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) return res.sendStatus(401);
jwt.verify(token, secretKey, (err, user) => {
if (err) return res.sendStatus(403);
req.user = user;
next();
});
};
app.get('/protected', authenticateToken, (req, res) => {
res.json({ message: 'This is a protected route', user: req.user });
});
app.listen(3000, () => console.log('Server running on port 3000'));
4. Accessing Protected Routes
- Middleware: You can protect routes by applying middleware that verifies the JWT before allowing access to the route. If the token is valid, the user is granted access; otherwise, an error is returned.
5. Token Expiration and Renewal
- Expiration: JWT tokens typically have an expiration time (
expclaim). After this time, the token is no longer valid, and the user must log in again to get a new token. - Token Renewal: You can implement a token refresh mechanism where the client can request a new token before the current one expires, without needing to log in again.
6. Security Considerations
- Secret Key Management: Keep your secret key secure and do not expose it publicly.
- Token Expiry: Use short-lived tokens and refresh tokens to minimize the risk if a token is compromised.
- HTTPS: Always use HTTPS to prevent token interception.
JWTs are a powerful way to handle authentication in web applications, especially when dealing with stateless APIs and distributed systems.