-
-
Save PaperNick/1fa0fa9f280b1d29a0a8f8e1b31df1e2 to your computer and use it in GitHub Desktop.
Auth0 JWT Verification
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
/** | |
* The MIT License (MIT) | |
* Copyright (c) 2022 PaperNick | |
* | |
* Resouces used: | |
* https://github.com/auth0/node-jwks-rsa | |
* https://github.com/auth0/node-jsonwebtoken | |
* https://auth0.com/blog/navigating-rs256-and-jwks/ | |
* https://gist.github.com/westmark/faee223e05bcbab433bfd4ed8e36fb5f | |
* https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/ | |
*/ | |
const AUTH0_AUTHORITY = 'https://auth0.tenant.com'; | |
const AUTH0_AUDIENCE = 'https://api.yourapp.com/'; | |
const jwksRsa = require('jwks-rsa'); | |
const jwt = require('jsonwebtoken'); | |
const jwksClient = jwksRsa({ | |
jwksUri: `${AUTH0_AUTHORITY.replace(/\/+$/, '')}/.well-known/jwks.json`, | |
}); | |
/** | |
* Attempt to parse the given JWT token. Throws an Error if token is invalid. | |
* | |
* @param {string} token JWT token without "Bearer " in the beginning | |
* @throws {Error} | |
* @returns {JwtPayload} | |
*/ | |
async function parseJwtToken(token) { | |
if (!token) { | |
throw new Error('Missing authorization token'); | |
} | |
// Decode without verifying if the signature is valid. | |
// Warning: do not access decoded token payload before verifying with jwt.verify() | |
const decodedToken = jwt.decode(token, { complete: true }); | |
if (!decodedToken || decodedToken.header.alg !== 'RS256') { | |
// Only RS256 tokens are supported at the moment | |
throw new Error('Invalid token or algorithm'); | |
} | |
let signingKey; | |
try { | |
signingKey = await jwksClient.getSigningKey(decodedToken.header.kid); | |
} catch (error) { | |
throw new Error('Could not retrieve key to verify token'); | |
} | |
try { | |
const jwtPayload = jwt.verify(token, signingKey.getPublicKey(), { audience: AUTH0_AUDIENCE }); | |
return jwtPayload; | |
} catch (error) { | |
throw new Error('The token is invalid or has expired'); | |
} | |
} | |
/** | |
* Attempt to parse the given JWT token. Returns undefined on error. | |
* | |
* @param {string} token | |
* @returns {JwtPayload|undefined} | |
*/ | |
async function parseJwtTokenQuiet(token) { | |
try { | |
return await parseJwtToken(token); | |
} catch (error) { | |
return; | |
} | |
} | |
module.exports = { parseJwtToken, parseJwtTokenQuiet }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment