Last active
July 27, 2023 10:48
-
-
Save philwilliammee/12ce15c4501b938e8c77c40bd13009e3 to your computer and use it in GitHub Desktop.
JWT-based email authentication middleware for Express.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SimpleEmailService from '../amazon/SimpleEmailService'; | |
import { Express, Request, Response, NextFunction } from 'express'; | |
import { sign, verify } from 'jsonwebtoken'; | |
const simpleEmailService = new SimpleEmailService(); | |
/** | |
* Middleware function to verify a JWT token. | |
*/ | |
export async function verifyToken( | |
req: Request, | |
res: Response, | |
next: NextFunction | |
) { | |
const { token } = req.body; | |
const decodedToken = decodeURIComponent(token); | |
try { | |
const jwtSecret = process.env.JWT_SECRET || 'secret'; | |
const decoded = verify(decodedToken, jwtSecret) as { | |
email: string; | |
}; | |
// Set the email in the request body so it can be used by the next middleware function. | |
req.body.email = decoded.email; | |
next(); // Continue to the next middleware function. | |
} catch (error) { | |
console.log(error); | |
return res.status(401).json({ | |
status: 401, // Unauthorized | |
message: 'Invalid or expired token', | |
}); | |
} | |
} | |
/** | |
* Middleware function to create a JWT token and send an email with a link to verify the email address. | |
*/ | |
export function createTokenAndSendEmail(htmlTemplate: string) { | |
return async (req: Request, res: Response, next: NextFunction) => { | |
const { email } = req.body; | |
const jwtSecret = process.env.JWT_SECRET || 'secret'; | |
const expiresIn = process.env.JWT_EXPIRES_IN || '24h'; | |
const token = sign({ email }, jwtSecret, { expiresIn }); | |
const encodedToken = encodeURIComponent(token); | |
const mailOptions = { | |
from: '[email protected]', | |
to: email, | |
subject: 'SSIT Dev Status: Verify your email address', | |
html: htmlTemplate.replace('${token}', encodedToken), | |
}; | |
await simpleEmailService.send(mailOptions); | |
next(); | |
}; | |
} | |
// Example Middleware Usage. | |
function requestAuthJwtController(req: Request, res: Response) { | |
return res.json({ | |
status: 200, | |
message: 'success', | |
}); | |
} | |
function verifyEmailController(req: Request, res: Response) { | |
// The email was set in the request body by the verifyToken middleware. | |
const { email } = req.body; | |
return res.json({ | |
status: 200, | |
message: 'success', | |
data: { email }, | |
}); | |
} | |
export function tokenAuthRoutes(app: Express) { | |
const tokenAuthUrl = process.env.TOKEN_AUTH_URL || 'https://localhost:4200/home'; | |
const htmlTemplate = ` | |
<p>Click the link below to verify your email address.</p> | |
<a href="${tokenAuthUrl}?token=\${token}">Verify Email</a> | |
`; | |
/** | |
* Step 1. The client requests a JWT token and an email is sent to the user. | |
* @todo this should have an async error handler. | |
*/ | |
app | |
.route('/api/auth/request-jwt-auth') | |
.post(createTokenAndSendEmail(htmlTemplate), requestAuthJwtController); | |
/** | |
* Step 2. The client clicks the link in the email and the email address is verified. | |
* Note: The verifyToken middleware verifies the JWT token. | |
* If the token is valid, the email address is set in the request body and the | |
* email address is returned in the response. | |
* If the token is invalid, a 401 response is returned. | |
*/ | |
app.route('/api/auth/verify-email').post(verifyToken, verifyEmailController); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment