Skip to content

Commit

Permalink
Publishing example examples/v7-jwt-verification
Browse files Browse the repository at this point in the history
  • Loading branch information
actions-user committed Feb 1, 2024
1 parent c025f5e commit c760f17
Show file tree
Hide file tree
Showing 11 changed files with 14,939 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
**NOTICE TO CONTRIBUTORS**

This repository is not actively monitored and any pull requests made to this repository will be closed/ignored.

Please submit the pull request to [edgio-docs/edgio-examples](https://github.com/edgio-docs/edgio-examples) instead.
18 changes: 18 additions & 0 deletions .github/workflows/edgio.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Deploy to Edgio

on:
workflow_dispatch:
push:

jobs:
deploy-to-edgio:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
- run: if [ -f yarn.lock ]; then yarn install; else npm ci; fi
- run: if [ -f yarn.lock ]; then yarn edgio:deploy -- --token=$EDGIO_DEPLOY_TOKEN; else npm run edgio:deploy -- --token=$EDGIO_DEPLOY_TOKEN; fi
env:
EDGIO_DEPLOY_TOKEN: ${{secrets.EDGIO_DEPLOY_TOKEN}}
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Edgio generated build directory
/.edgio

/node_modules
.env
51 changes: 50 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,50 @@
# edgio-v7-jwt-verification-example
# JWT Verification using Edge Functions

https://edgio-community-examples-v7-jwt-verification-test.glb.edgio.link/

## Description

This repository provides example code for verifying JSON Web Tokens (JWT) using Edge Functions. It features an example of how to verify a JWT and return a 401 response if the token is invalid.

## Prerequisites

**NOTE**: To use this project, you must be an Edgio customer and signed up for the Edge Functions. See our [Edge Functions documentation](https://docs.edg.io/guides/v7/edge-functions) for information on activating this feature.

The system requirements include Node.js v16 or higher, and a UNIX-like system (Linux or macOS). The project code is written in JavaScript.

## Setup and Installation

1. Ensure you meet the prerequisites.
2. Clone the repository to your local machine.
3. Run `npm install` in the repository directory.

## Getting Started

After setting up the project, run `npm run edgio:dev` to start a local development server to test the example functions.

To deploy the project to Edgio, use the command `npm run edgio:deploy`. Note that deployment to Edgio requires you to be
logged into Edgio CLI which can be done via `npm run edgio login` and following the instructions.

## Known Issues and Limitations

Currently

* We only support JavaScript-based code
* Each request has a 60-second (wall time) timeout limit
* Each request is limited to 50ms of CPU time
* Each request is limited to 2MB of memory
* An Edgio Function can make fetch requests only to origins defined in your property configuration
file (`edgio.config.js`).

We're looking forward to feedback from our customers about these limitations and how we can improve the product.

## Support

If you have any queries or face issues with this project, please don't hesitate to contact
the [Edgio team](https://edg.io/contact-support/).

## License

[Creative Commons Attribution 4.0 International Public License](LICENSE-CONTENT) for the documentation.

[MIT License](LICENSE-CODE) for the code.
58 changes: 58 additions & 0 deletions edge-functions/JWT.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Buffer } from 'buffer';
import * as Base64 from 'crypto-js/enc-base64url';
import { HmacSHA256, HmacSHA384, HmacSHA512 } from 'crypto-js';

// 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 {
constructor(token, 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() {
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;
}

// Returns the algorithm used in JWT
algUsed() {
return this.header.alg;
}
}
38 changes: 38 additions & 0 deletions edge-functions/validate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
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) {
// 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();

// If valid, update response with additional JWT info
if (isValid) {
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 : 401, // 200 OK for valid token, 401 for invalid
headers: { 'Content-Type': 'application/json' }, // Set response content type
});
}
90 changes: 90 additions & 0 deletions edgio.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// This file was automatically added by edgio init.
// You should commit this file to source control.
// 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-verification',

// The name of the organization in Edgio to which this app should be deployed.
// organization: 'my-organization-name',

// Overrides the default path to the routes file. The path should be relative to the root of your app.
// routes: 'routes.js',

// When set to true or omitted entirely, Edgio includes the deployment number in the cache key,
// effectively purging the cache each time you deploy.
purgeCacheOnDeploy: true,
// purgeCacheOnDeploy: false,

origins: [
{
// The name of the backend 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',

// The list of origin hosts to which to connect
hosts: [
{
// The domain name or IP address of the origin server
location: 'httpbin.org',
},
],

tls_verify: {
use_sni: true,
sni_hint_and_strict_san_check: 'httpbin.org',
},

// Uncomment the following to configure a shield
// shields: { us_east: 'DCD' },
},
],

// Uncomment the following to specify environment specific configs
// environments: {
// production: {
// hostnames: [{ hostname: 'www.mysite.com' }],
// },
// staging: {
// hostnames: [{ hostname: 'staging.mysite.com' }],
// origins: [
// {
// name: 'origin',
// hosts: [{ location: 'staging-origin.mysite.com' }],
// override_host_header: 'staging-origin.mysite.com',
// tls_verify: {
// use_sni: true,
// sni_hint_and_strict_san_check: 'staging-origin.mysite.com',
// },
// shields: { us_east: 'DCD' },
// },
// ],
// },
// },

// Options for hosting serverless functions on Edgio
// serverless: {
// // Set to true to include all packages listed in the dependencies property of package.json when deploying to Edgio.
// // This option generally isn't needed as Edgio automatically includes all modules imported by your code in the bundle that
// // is uploaded during deployment
// includeNodeModules: true,
//
// // Include additional paths that are dynamically loaded by your app at runtime here when building the serverless bundle.
// include: ['views/**/*'],
// },

// The maximum number of URLs that will be concurrently prerendered during deployment when static prerendering is enabled.
// Defaults to 200, which is the maximum allowed value.
// prerenderConcurrency: 200,

// A list of glob patterns identifying which source files should be uploaded when running edgio deploy --includeSources.
// This option is primarily used to share source code with Edgio support personnel for the purpose of debugging. If omitted,
// edgio deploy --includeSources will result in all files which are not gitignored being uploaded to Edgio.
//
// sources : [
// '**/*', // include all files
// '!(**/secrets/**/*)', // except everything in the secrets directory
// ],
};
Loading

0 comments on commit c760f17

Please sign in to comment.