From ead248be5cd09eb4561f63ea4ab6881641e670fb Mon Sep 17 00:00:00 2001 From: Tristan Lee Date: Thu, 1 Feb 2024 10:03:18 -0500 Subject: [PATCH] Apply style and comment changes --- .../v7-jwt-verification/edge-functions/JWT.js | 74 ++++---- .../edge-functions/validate.js | 45 +++-- examples/v7-jwt-verification/edgio.config.js | 10 +- examples/v7-jwt-verification/routes.js | 2 +- .../v7-jwt-verification/static/validate.html | 176 ++++++++++++------ 5 files changed, 198 insertions(+), 109 deletions(-) diff --git a/examples/v7-jwt-verification/edge-functions/JWT.js b/examples/v7-jwt-verification/edge-functions/JWT.js index 9cdc47b7b..57aa8a734 100644 --- a/examples/v7-jwt-verification/edge-functions/JWT.js +++ b/examples/v7-jwt-verification/edge-functions/JWT.js @@ -1,54 +1,58 @@ -import { Buffer } from 'buffer' -import * as Base64 from 'crypto-js/enc-base64url' -import { HmacSHA256, HmacSHA384, HmacSHA512 } from 'crypto-js' +import { Buffer } from 'buffer'; +import * as Base64 from 'crypto-js/enc-base64url'; +import { HmacSHA256, HmacSHA384, HmacSHA512 } from 'crypto-js'; -const base64decode = (str) => Buffer.from(str, 'base64').toString() +// Function to decode base64 strings +const base64decode = (str) => Buffer.from(str, 'base64').toString(); +// Hashing functions mapped to JWT algorithms const hashLibraries = { HS256: HmacSHA256, HS384: HmacSHA384, HS512: HmacSHA512, -} +}; export class JWT { - // JWT validation process: - // 1. Split the token by '.' to get the header (json), payload (json), and signature (string). - // 2. Calculate a signature using the algorithm in the header (hardcoded here) to join the header and payload with a - // '.', and hash it using a secret value - // 3. Compare the calculated signature with the one from the token. If they match, the token is valid. If not, the - // token has been tampered with. - constructor(token, secret) { - const [ header_base64, payload_base64, origSignature ] = token.split('.') - - this.header_base64 = header_base64 - this.payload_base64 = payload_base64 - - this.header = JSON.parse(base64decode(header_base64)) - this.payload = JSON.parse(base64decode(payload_base64)) - - this.origSignature = origSignature - - this.hasher = hashLibraries[this.header.alg] - this.secret = secret + const [header_base64, payload_base64, origSignature] = token.split('.'); + + this.header_base64 = header_base64; + this.payload_base64 = payload_base64; + + try { + // Decode header and payload from base64 + this.header = JSON.parse(base64decode(header_base64)); + this.payload = JSON.parse(base64decode(payload_base64)); + } catch (e) { + // Invalid payload or header, initialize empty objects + this.header = {}; + this.payload = {}; + } + + this.origSignature = origSignature; + this.hasher = hashLibraries[this.header.alg]; + this.secret = secret; } + // Validates the JWT token validate() { - console.log(`validating token using ${this.header.alg} algorithm.`) - const calculatedSignature = Base64.stringify( - this.hasher( - `${this.header_base64}.${this.payload_base64}`, - this.secret - ) - ) - return calculatedSignature === this.origSignature + try { + const calculatedSignature = Base64.stringify( + this.hasher(`${this.header_base64}.${this.payload_base64}`, this.secret) + ); + return calculatedSignature === this.origSignature; + } catch (e) { + return false; + } } + // Returns the payload object payloadObject() { - return this.payload + return this.payload; } + // Returns the algorithm used in JWT algUsed() { - return this.header.alg + return this.header.alg; } -} \ No newline at end of file +} diff --git a/examples/v7-jwt-verification/edge-functions/validate.js b/examples/v7-jwt-verification/edge-functions/validate.js index 56ef1178d..b709b3ec5 100644 --- a/examples/v7-jwt-verification/edge-functions/validate.js +++ b/examples/v7-jwt-verification/edge-functions/validate.js @@ -1,21 +1,38 @@ -import { JWT } from './JWT.js' +import { JWT } from './JWT.js'; +/** + * Handle an HTTP request to validate a JWT. + * + * @param {Request} request - The incoming HTTP request. + * @param {any} context - Context providing runtime information. + * @returns {Response} HTTP response with validation result. + */ export async function handleHttpRequest(request, context) { - const token = await request.text() - const secret = context.environmentVars['JWT_SECRET'] || '' - const resp = { - valid: false - } + // Extract the JWT token from the request body + const { token } = await request.json(); + + // Retrieve the secret key from environment variables + const secret = context.environmentVars['JWT_SECRET'] || 'your-256-bit-secret'; + + // Initialize response structure + const resp = { valid: false }; + + // Create JWT instance with the token and secret + const jwt = new JWT(token, secret); + + // Validate the JWT + const isValid = jwt.validate(); - const jwt = new JWT(token, secret) - const isValid = jwt.validate() + // If valid, update response with additional JWT info if (isValid) { - resp.valid = true - resp.payload = jwt.payloadObject() - resp.alg = jwt.algUsed() + resp.valid = true; + resp.payload = jwt.payloadObject(); // Extract payload + resp.alg = jwt.algUsed(); // Extract algorithm used } + // Return the response with appropriate HTTP status code return new Response(JSON.stringify(resp), { - status: isValid ? 200 : 403 - }) -} \ No newline at end of file + status: isValid ? 200 : 403, // 200 OK for valid token, 403 Forbidden for invalid + headers: { 'Content-Type': 'application/json' }, // Set response content type + }); +} diff --git a/examples/v7-jwt-verification/edgio.config.js b/examples/v7-jwt-verification/edgio.config.js index a2312f93f..2230be1de 100644 --- a/examples/v7-jwt-verification/edgio.config.js +++ b/examples/v7-jwt-verification/edgio.config.js @@ -3,7 +3,7 @@ // Learn more about this file at https://docs.edg.io/guides/edgio_config module.exports = { // The name of the site in Edgio to which this app should be deployed. - name: "ef-jwt-validate", + name: 'ef-jwt-verification', // The name of the organization in Edgio to which this app should be deployed. // organization: 'my-organization-name', @@ -19,22 +19,22 @@ module.exports = { origins: [ { // The name of the backend origin - name: "origin", + name: 'origin', // Use the following to override the host header sent from the browser when connecting to the origin - override_host_header: "httpbin.org", + override_host_header: 'httpbin.org', // The list of origin hosts to which to connect hosts: [ { // The domain name or IP address of the origin server - location: "httpbin.org", + location: 'httpbin.org', }, ], tls_verify: { use_sni: true, - sni_hint_and_strict_san_check: "httpbin.org", + sni_hint_and_strict_san_check: 'httpbin.org', }, // Uncomment the following to configure a shield diff --git a/examples/v7-jwt-verification/routes.js b/examples/v7-jwt-verification/routes.js index b8c7b424b..f5264a07e 100644 --- a/examples/v7-jwt-verification/routes.js +++ b/examples/v7-jwt-verification/routes.js @@ -4,7 +4,7 @@ import { Router, edgioRoutes } from '@edgio/core'; export default new Router() .use(edgioRoutes) - .get('/validate', ({ serveStatic }) => { + .get('/', ({ serveStatic }) => { serveStatic('static/validate.html'); }) .post('/jwt', { diff --git a/examples/v7-jwt-verification/static/validate.html b/examples/v7-jwt-verification/static/validate.html index 212296be7..0d64a3d4c 100644 --- a/examples/v7-jwt-verification/static/validate.html +++ b/examples/v7-jwt-verification/static/validate.html @@ -1,58 +1,126 @@ + - - - - JWT Validator - - - -
-
-
- Your token: - -
- -
+ + + + JWT Validator + + + +
+

JWT Validator

+
+
+ Enter Your Token: + +
+ +
-
-

Click "Validate" above.

+

+ You can generate a test token using the default signing key + your-256-bit-secret at + jwt.io. Valid algorithms for this example include HS256, + HS384, and HS512. +

+ +
+

Click "Validate" to verify your token.

+
-
- - - \ No newline at end of file + + +