-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathauth.js
More file actions
94 lines (77 loc) · 2.33 KB
/
Copy pathauth.js
File metadata and controls
94 lines (77 loc) · 2.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
const jwt = require('jsonwebtoken')
const { OAuthError } = require('./errors')
let publicKey
function setPublicKey (key) {
publicKey = key
}
function getPublicKey () {
return publicKey
}
// Middleware to verify JWT token from Authorization header
function authenticateToken (req, res, next) {
const authHeader = req.headers.authorization
const token = authHeader && authHeader.split(' ')[1]
if (!token) {
return next(new OAuthError('invalid_request', 'Missing authorization token'))
}
try {
const decoded = jwt.verify(token, publicKey, {
algorithms: ['RS256']
})
req.user = decoded
next()
} catch (err) {
if (err.name === 'TokenExpiredError') {
return next(new OAuthError('invalid_grant', 'Token has expired'))
}
return next(new OAuthError('invalid_grant', 'Invalid token'))
}
}
// Middleware to verify Bearer token (access token)
function authenticateBearerToken (req, res, next) {
const authHeader = req.headers.authorization
const token = authHeader && authHeader.split(' ')[1]
if (!token) {
return next(new OAuthError('invalid_request', 'Missing bearer token'))
}
try {
const decoded = jwt.verify(token, publicKey, {
algorithms: ['RS256']
})
// Ensure token is an access token (has token_type set or no token_type for backward compat)
// ID tokens will be verified separately via bearer check
if (decoded.token_type && decoded.token_type !== 'access') {
throw new Error('Invalid token type')
}
req.user = decoded
next()
} catch (err) {
if (err.name === 'TokenExpiredError') {
return next(new OAuthError('invalid_grant', 'Token has expired'))
}
return next(new OAuthError('invalid_grant', 'Invalid token'))
}
}
// Middleware to verify scope
function requireScope (...scopes) {
return (req, res, next) => {
if (!req.user) {
return next(new OAuthError('invalid_request', 'User not authenticated'))
}
const userScopes = (req.user.scope || '').split(' ').filter(s => s)
const hasScope = scopes.some(scope =>
userScopes.includes(scope)
)
if (!hasScope) {
return next(new OAuthError('insufficient_scope', `Required scope: ${scopes.join(' or ')}`))
}
next()
}
}
module.exports = {
authenticateToken,
authenticateBearerToken,
requireScope,
setPublicKey,
getPublicKey
}