1- const axios = require ( " axios" ) ;
2- const jwt = require ( " jsonwebtoken" ) ;
3- const jwkToPem = require ( " jwk-to-pem" ) ;
1+ const axios = require ( ' axios' ) ;
2+ const jwt = require ( ' jsonwebtoken' ) ;
3+ const jwkToPem = require ( ' jwk-to-pem' ) ;
44const config = require ( '../../config' ) ;
55
66/**
@@ -10,97 +10,102 @@ const config = require('../../config');
1010 */
1111async function getJwks ( authorityUrl ) {
1212 try {
13- const { data } = await axios . get ( `${ authorityUrl } /.well-known/openid-configuration` ) ;
14- const jwksUri = data . jwks_uri ;
13+ const { data } = await axios . get ( `${ authorityUrl } /.well-known/openid-configuration` ) ;
14+ const jwksUri = data . jwks_uri ;
1515
16- const { data : jwks } = await axios . get ( jwksUri ) ;
17- return jwks . keys ;
16+ const { data : jwks } = await axios . get ( jwksUri ) ;
17+ return jwks . keys ;
1818 } catch ( error ) {
19- console . error ( " Error fetching JWKS:" , error ) ;
20- throw new Error ( " Failed to fetch JWKS" ) ;
19+ console . error ( ' Error fetching JWKS:' , error ) ;
20+ throw new Error ( ' Failed to fetch JWKS' ) ;
2121 }
2222}
2323
2424/**
2525 * Validate a JWT token using the OIDC configuration.
2626 * @param {* } token the JWT token
2727 * @param {* } authorityUrl the OIDC authority URL
28- * @param {* } clientID the OIDC client ID
28+ * @param {* } clientID the OIDC client ID
2929 * @param {* } expectedAudience the expected audience for the token
3030 * @return {Promise<object> } the verified payload or an error
3131 */
3232async function validateJwt ( token , authorityUrl , clientID , expectedAudience ) {
3333 try {
34- const jwks = await getJwks ( authorityUrl ) ;
34+ const jwks = await getJwks ( authorityUrl ) ;
3535
36- const decodedHeader = await jwt . decode ( token , { complete : true } ) ;
37- if ( ! decodedHeader || ! decodedHeader . header || ! decodedHeader . header . kid ) {
38- throw new Error ( " Invalid JWT: Missing key ID (kid)" ) ;
39- }
36+ const decodedHeader = await jwt . decode ( token , { complete : true } ) ;
37+ if ( ! decodedHeader || ! decodedHeader . header || ! decodedHeader . header . kid ) {
38+ throw new Error ( ' Invalid JWT: Missing key ID (kid)' ) ;
39+ }
4040
41- const { kid } = decodedHeader . header ;
42- const jwk = jwks . find ( ( key ) => key . kid === kid ) ;
43- if ( ! jwk ) {
44- throw new Error ( " No matching key found in JWKS" ) ;
45- }
41+ const { kid } = decodedHeader . header ;
42+ const jwk = jwks . find ( ( key ) => key . kid === kid ) ;
43+ if ( ! jwk ) {
44+ throw new Error ( ' No matching key found in JWKS' ) ;
45+ }
4646
47- const pubKey = jwkToPem ( jwk ) ;
47+ const pubKey = jwkToPem ( jwk ) ;
4848
49- const verifiedPayload = jwt . verify ( token , pubKey , {
50- algorithms : [ " RS256" ] ,
51- issuer : authorityUrl ,
52- audience : expectedAudience ,
53- } ) ;
49+ const verifiedPayload = jwt . verify ( token , pubKey , {
50+ algorithms : [ ' RS256' ] ,
51+ issuer : authorityUrl ,
52+ audience : expectedAudience ,
53+ } ) ;
5454
55- if ( verifiedPayload . azp !== clientID ) {
56- throw new Error ( " JWT client ID does not match" ) ;
57- }
55+ if ( verifiedPayload . azp !== clientID ) {
56+ throw new Error ( ' JWT client ID does not match' ) ;
57+ }
5858
59- return { verifiedPayload } ;
59+ return { verifiedPayload } ;
6060 } catch ( error ) {
61- const errorMessage = `JWT validation failed: ${ error . message } \n` ;
62- console . error ( errorMessage ) ;
63- return { error : errorMessage } ;
61+ const errorMessage = `JWT validation failed: ${ error . message } \n` ;
62+ console . error ( errorMessage ) ;
63+ return { error : errorMessage } ;
6464 }
6565}
6666
6767const jwtAuthHandler = ( ) => {
6868 return async ( req , res , next ) => {
6969 const apiAuthMethods = config . getAPIAuthMethods ( ) ;
70- const jwtAuthMethod = apiAuthMethods . find ( ( method ) => method . type . toLowerCase ( ) === "jwt" ) ;
71- if ( ! jwtAuthMethod ) {
72- return next ( ) ;
73- }
74-
75- if ( req . isAuthenticated ( ) ) {
76- return next ( ) ;
77- }
78-
79- const token = req . header ( "Authorization" ) ;
80- if ( ! token ) {
81- return res . status ( 401 ) . send ( "No token provided\n" ) ;
82- }
83-
84- const { clientID, authorityURL, expectedAudience } = jwtAuthMethod . jwtConfig ;
85- const audience = expectedAudience || clientID ;
86-
87- if ( ! authorityURL ) {
88- return res . status ( 500 ) . send ( "OIDC authority URL is not configured\n" ) ;
89- }
90-
91- if ( ! clientID ) {
92- return res . status ( 500 ) . send ( "OIDC client ID is not configured\n" ) ;
93- }
94-
95- const tokenParts = token . split ( " " ) ;
96- const { verifiedPayload, error } = await validateJwt ( tokenParts [ 1 ] , authorityURL , audience , clientID ) ;
97- if ( error ) {
98- return res . status ( 401 ) . send ( error ) ;
99- }
100-
101- req . user = verifiedPayload ;
70+ const jwtAuthMethod = apiAuthMethods . find ( ( method ) => method . type . toLowerCase ( ) === 'jwt' ) ;
71+ if ( ! jwtAuthMethod ) {
10272 return next ( ) ;
103- }
104- }
73+ }
74+
75+ if ( req . isAuthenticated ( ) ) {
76+ return next ( ) ;
77+ }
78+
79+ const token = req . header ( 'Authorization' ) ;
80+ if ( ! token ) {
81+ return res . status ( 401 ) . send ( 'No token provided\n' ) ;
82+ }
83+
84+ const { clientID, authorityURL, expectedAudience } = jwtAuthMethod . jwtConfig ;
85+ const audience = expectedAudience || clientID ;
86+
87+ if ( ! authorityURL ) {
88+ return res . status ( 500 ) . send ( 'OIDC authority URL is not configured\n' ) ;
89+ }
90+
91+ if ( ! clientID ) {
92+ return res . status ( 500 ) . send ( 'OIDC client ID is not configured\n' ) ;
93+ }
94+
95+ const tokenParts = token . split ( ' ' ) ;
96+ const { verifiedPayload, error } = await validateJwt (
97+ tokenParts [ 1 ] ,
98+ authorityURL ,
99+ audience ,
100+ clientID ,
101+ ) ;
102+ if ( error ) {
103+ return res . status ( 401 ) . send ( error ) ;
104+ }
105+
106+ req . user = verifiedPayload ;
107+ return next ( ) ;
108+ } ;
109+ } ;
105110
106111module . exports = jwtAuthHandler ;
0 commit comments