Skip to content

Commit 2d35345

Browse files
committed
Apply style and comment changes
1 parent 62acf5f commit 2d35345

File tree

5 files changed

+198
-109
lines changed

5 files changed

+198
-109
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,58 @@
1-
import { Buffer } from 'buffer'
2-
import * as Base64 from 'crypto-js/enc-base64url'
3-
import { HmacSHA256, HmacSHA384, HmacSHA512 } from 'crypto-js'
1+
import { Buffer } from 'buffer';
2+
import * as Base64 from 'crypto-js/enc-base64url';
3+
import { HmacSHA256, HmacSHA384, HmacSHA512 } from 'crypto-js';
44

5-
const base64decode = (str) => Buffer.from(str, 'base64').toString()
5+
// Function to decode base64 strings
6+
const base64decode = (str) => Buffer.from(str, 'base64').toString();
67

8+
// Hashing functions mapped to JWT algorithms
79
const hashLibraries = {
810
HS256: HmacSHA256,
911
HS384: HmacSHA384,
1012
HS512: HmacSHA512,
11-
}
13+
};
1214

1315
export class JWT {
14-
// JWT validation process:
15-
// 1. Split the token by '.' to get the header (json), payload (json), and signature (string).
16-
// 2. Calculate a signature using the algorithm in the header (hardcoded here) to join the header and payload with a
17-
// '.', and hash it using a secret value
18-
// 3. Compare the calculated signature with the one from the token. If they match, the token is valid. If not, the
19-
// token has been tampered with.
20-
2116
constructor(token, secret) {
22-
const [ header_base64, payload_base64, origSignature ] = token.split('.')
23-
24-
this.header_base64 = header_base64
25-
this.payload_base64 = payload_base64
26-
27-
this.header = JSON.parse(base64decode(header_base64))
28-
this.payload = JSON.parse(base64decode(payload_base64))
29-
30-
this.origSignature = origSignature
31-
32-
this.hasher = hashLibraries[this.header.alg]
33-
this.secret = secret
17+
const [header_base64, payload_base64, origSignature] = token.split('.');
18+
19+
this.header_base64 = header_base64;
20+
this.payload_base64 = payload_base64;
21+
22+
try {
23+
// Decode header and payload from base64
24+
this.header = JSON.parse(base64decode(header_base64));
25+
this.payload = JSON.parse(base64decode(payload_base64));
26+
} catch (e) {
27+
// Invalid payload or header, initialize empty objects
28+
this.header = {};
29+
this.payload = {};
30+
}
31+
32+
this.origSignature = origSignature;
33+
this.hasher = hashLibraries[this.header.alg];
34+
this.secret = secret;
3435
}
3536

37+
// Validates the JWT token
3638
validate() {
37-
console.log(`validating token using ${this.header.alg} algorithm.`)
38-
const calculatedSignature = Base64.stringify(
39-
this.hasher(
40-
`${this.header_base64}.${this.payload_base64}`,
41-
this.secret
42-
)
43-
)
44-
return calculatedSignature === this.origSignature
39+
try {
40+
const calculatedSignature = Base64.stringify(
41+
this.hasher(`${this.header_base64}.${this.payload_base64}`, this.secret)
42+
);
43+
return calculatedSignature === this.origSignature;
44+
} catch (e) {
45+
return false;
46+
}
4547
}
4648

49+
// Returns the payload object
4750
payloadObject() {
48-
return this.payload
51+
return this.payload;
4952
}
5053

54+
// Returns the algorithm used in JWT
5155
algUsed() {
52-
return this.header.alg
56+
return this.header.alg;
5357
}
54-
}
58+
}
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,38 @@
1-
import { JWT } from './JWT.js'
1+
import { JWT } from './JWT.js';
22

3+
/**
4+
* Handle an HTTP request to validate a JWT.
5+
*
6+
* @param {Request} request - The incoming HTTP request.
7+
* @param {any} context - Context providing runtime information.
8+
* @returns {Response} HTTP response with validation result.
9+
*/
310
export async function handleHttpRequest(request, context) {
4-
const token = await request.text()
5-
const secret = context.environmentVars['JWT_SECRET'] || ''
6-
const resp = {
7-
valid: false
8-
}
11+
// Extract the JWT token from the request body
12+
const { token } = await request.json();
13+
14+
// Retrieve the secret key from environment variables
15+
const secret = context.environmentVars['JWT_SECRET'] || 'your-256-bit-secret';
16+
17+
// Initialize response structure
18+
const resp = { valid: false };
19+
20+
// Create JWT instance with the token and secret
21+
const jwt = new JWT(token, secret);
22+
23+
// Validate the JWT
24+
const isValid = jwt.validate();
925

10-
const jwt = new JWT(token, secret)
11-
const isValid = jwt.validate()
26+
// If valid, update response with additional JWT info
1227
if (isValid) {
13-
resp.valid = true
14-
resp.payload = jwt.payloadObject()
15-
resp.alg = jwt.algUsed()
28+
resp.valid = true;
29+
resp.payload = jwt.payloadObject(); // Extract payload
30+
resp.alg = jwt.algUsed(); // Extract algorithm used
1631
}
1732

33+
// Return the response with appropriate HTTP status code
1834
return new Response(JSON.stringify(resp), {
19-
status: isValid ? 200 : 403
20-
})
21-
}
35+
status: isValid ? 200 : 403, // 200 OK for valid token, 403 Forbidden for invalid
36+
headers: { 'Content-Type': 'application/json' }, // Set response content type
37+
});
38+
}

examples/v7-jwt-verification/edgio.config.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// Learn more about this file at https://docs.edg.io/guides/edgio_config
44
module.exports = {
55
// The name of the site in Edgio to which this app should be deployed.
6-
name: "ef-jwt-validate",
6+
name: 'ef-jwt-verification',
77

88
// The name of the organization in Edgio to which this app should be deployed.
99
// organization: 'my-organization-name',
@@ -19,22 +19,22 @@ module.exports = {
1919
origins: [
2020
{
2121
// The name of the backend origin
22-
name: "origin",
22+
name: 'origin',
2323

2424
// Use the following to override the host header sent from the browser when connecting to the origin
25-
override_host_header: "httpbin.org",
25+
override_host_header: 'httpbin.org',
2626

2727
// The list of origin hosts to which to connect
2828
hosts: [
2929
{
3030
// The domain name or IP address of the origin server
31-
location: "httpbin.org",
31+
location: 'httpbin.org',
3232
},
3333
],
3434

3535
tls_verify: {
3636
use_sni: true,
37-
sni_hint_and_strict_san_check: "httpbin.org",
37+
sni_hint_and_strict_san_check: 'httpbin.org',
3838
},
3939

4040
// Uncomment the following to configure a shield

examples/v7-jwt-verification/routes.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Router, edgioRoutes } from '@edgio/core';
44

55
export default new Router()
66
.use(edgioRoutes)
7-
.get('/validate', ({ serveStatic }) => {
7+
.get('/', ({ serveStatic }) => {
88
serveStatic('static/validate.html');
99
})
1010
.post('/jwt', {
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,126 @@
1+
<!DOCTYPE html>
12
<html lang="en">
2-
<head>
3-
<meta charset="UTF-8">
4-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
5-
<title>JWT Validator</title>
6-
<style type="text/css">
7-
.wrapper {
8-
max-width: 640px;
9-
margin: 1rem auto;
10-
}
11-
fieldset {
12-
margin-bottom: 1rem;
13-
}
14-
</style>
15-
</head>
16-
<body>
17-
<div class="wrapper">
18-
<form action="#" id="validator">
19-
<fieldset>
20-
<legend for="token">Your token:</legend>
21-
<textarea name="token" id="token" cols="70" rows="10"></textarea>
22-
</fieldset>
23-
<button type="submit">Validate</button>
24-
</form>
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>JWT Validator</title>
7+
<style type="text/css">
8+
body {
9+
font-family: Arial, sans-serif;
10+
background-color: #f4f4f4;
11+
color: #333;
12+
}
13+
.wrapper {
14+
max-width: 640px;
15+
margin: 2rem auto;
16+
padding: 1rem;
17+
background: white;
18+
border-radius: 8px;
19+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
20+
}
21+
fieldset {
22+
border: 1px solid #ddd;
23+
padding: 0.5rem;
24+
}
25+
textarea {
26+
width: calc(100% - 1rem); /* Adjust width to prevent overflow */
27+
padding: 0.25rem;
28+
border: 1px solid #ddd;
29+
border-radius: 4px;
30+
margin-top: 0.5rem;
31+
box-sizing: border-box; /* Include padding and border in the element's total width and height */
32+
}
33+
button {
34+
padding: 0.5rem 1rem;
35+
color: white;
36+
background-color: #007bff;
37+
border: none;
38+
border-radius: 4px;
39+
cursor: pointer;
40+
margin-top: 1rem;
41+
}
42+
button:hover {
43+
background-color: #0056b3;
44+
}
45+
#results {
46+
margin-top: 1rem;
47+
padding: 1rem;
48+
background-color: #eee;
49+
border-radius: 4px;
50+
}
51+
</style>
52+
</head>
53+
<body>
54+
<div class="wrapper">
55+
<h1>JWT Validator</h1>
56+
<form id="validator">
57+
<fieldset>
58+
<legend>Enter Your Token:</legend>
59+
<textarea
60+
name="token"
61+
id="token"
62+
rows="10"
63+
placeholder="Paste your JWT here..."
64+
>
65+
eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJjb21tZW50IjoiRWRnZSBmdW5jdGlvbnMgYXJlIHN3ZWV0ISJ9.hc0nVeZWhE6MEf-CHJwljTY3uo6qqm8q_V_0zwm34tFALrjJDAa0CL3oUEehMRNdt3PQdcuWBgzMUqKVUWMRVQ</textarea
66+
>
67+
</fieldset>
68+
<button type="submit">Validate</button>
69+
</form>
2570

26-
<div id="results">
27-
<p>Click "Validate" above.</p>
71+
<p>
72+
You can generate a test token using the default signing key
73+
<code>your-256-bit-secret</code> at
74+
<a href="https://jwt.io" target="_blank" rel="noopener noreferrer"
75+
>jwt.io</a
76+
>. Valid algorithms for this example include <code>HS256</code>,
77+
<code>HS384</code>, and <code>HS512</code>.
78+
</p>
79+
80+
<div id="results">
81+
<p>Click "Validate" to verify your token.</p>
82+
</div>
2883
</div>
29-
</div>
3084

31-
<script type="text/javascript">
32-
const form = document.getElementById('validator')
33-
form.addEventListener('submit', async (e) => {
34-
e.preventDefault()
35-
const token = form.querySelector('textarea[name="token"]').value
36-
let resultString = ''
37-
try {
38-
const resp = await fetch('/jwt', {
39-
method: 'POST',
40-
body: token
41-
})
42-
const data = await resp.json()
43-
console.log(data)
44-
if (data.valid) {
45-
resultString = `<p>Token successfully validated using ${data.alg}. Refresh the page to try another token.</p><p>Payload:</p><pre>${JSON.stringify(data.payload)}</pre>`
46-
} else {
47-
resultString = '<p>An error occurred validating the token.</p>'
48-
}
49-
} catch (e) {
50-
resultString = '<p>An error occurred validating the token.</p>'
51-
console.error(e)
52-
} finally {
53-
document.getElementById('results').innerHTML = resultString
54-
}
55-
})
56-
</script>
57-
</body>
58-
</html>
85+
<script type="text/javascript">
86+
document
87+
.getElementById('validator')
88+
.addEventListener('submit', async (e) => {
89+
e.preventDefault();
90+
const token = document.getElementById('token').value;
91+
let resultString = '';
92+
93+
try {
94+
const response = await fetch('/jwt', {
95+
method: 'POST',
96+
headers: { 'Content-Type': 'application/json' },
97+
body: JSON.stringify({ token }),
98+
});
99+
100+
if (!response.ok) {
101+
throw new Error(`Server error occurred. Response code: ${response.status}, Response body: ${JSON.stringify(await response.json())}`);
102+
}
103+
104+
const data = await response.json();
105+
106+
if (data.valid) {
107+
resultString = `<p>Token successfully validated using ${
108+
data.alg
109+
}.</p><p>Payload:</p><pre>${JSON.stringify(
110+
data.payload,
111+
null,
112+
2
113+
)}</pre>`;
114+
} else {
115+
resultString = '<p>An error occurred validating the token.</p>';
116+
}
117+
} catch (error) {
118+
resultString = `<p>${error.message}</p>`;
119+
console.error('Error:', error);
120+
} finally {
121+
document.getElementById('results').innerHTML = resultString;
122+
}
123+
});
124+
</script>
125+
</body>
126+
</html>

0 commit comments

Comments
 (0)