A social knowledge tool for researchers built on ATProto
1import { Request, Response, NextFunction } from 'express';
2import { ITokenService } from '../../../../modules/user/application/services/ITokenService';
3
4export interface AuthenticatedRequest extends Request {
5 did?: string;
6}
7
8export class AuthMiddleware {
9 constructor(private tokenService: ITokenService) {}
10
11 public ensureAuthenticated() {
12 return async (
13 req: AuthenticatedRequest,
14 res: Response,
15 next: NextFunction,
16 ): Promise<void> => {
17 try {
18 // Extract token from Authorization header
19 const authHeader = req.headers.authorization;
20 if (!authHeader || !authHeader.startsWith('Bearer ')) {
21 res.status(401).json({ message: 'No access token provided' });
22 return; // Stop execution after sending a response
23 }
24
25 const token = authHeader.substring(7); // Remove 'Bearer ' prefix
26
27 // Validate token
28 const didResult = await this.tokenService.validateToken(token);
29
30 if (didResult.isErr() || !didResult.value) {
31 res.status(403).json({ message: 'Invalid or expired token' });
32 return; // Stop execution after sending a response
33 }
34
35 // Attach user DID to request for use in controllers
36 req.did = didResult.value;
37
38 // Continue to the next middleware or controller
39 next();
40 } catch (error) {
41 res.status(500).json({ message: 'Authentication error' });
42 }
43 };
44 }
45
46 public optionalAuth() {
47 return async (
48 req: AuthenticatedRequest,
49 res: Response,
50 next: NextFunction,
51 ) => {
52 try {
53 // Extract token from Authorization header
54 const authHeader = req.headers.authorization;
55 if (!authHeader || !authHeader.startsWith('Bearer ')) {
56 // No token, but that's okay - continue without authentication
57 return next();
58 }
59
60 const token = authHeader.substring(7); // Remove 'Bearer ' prefix
61
62 // Validate token
63 const didResult = await this.tokenService.validateToken(token);
64
65 if (didResult.isOk() && didResult.value) {
66 // Attach user DID to request for use in controllers
67 req.did = didResult.value;
68 }
69
70 // Continue to the controller regardless of token validity
71 next();
72 } catch (error) {
73 // Continue without authentication in case of error
74 next();
75 }
76 };
77 }
78}