Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JWT Signing #212

Merged
merged 5 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions edgecompute/examples/authentication/jwt-signing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# JWT Signing

_Keyword(s):_ jwt, authentication<br>

This project provides an Akamai Edgeworker solution for signing JSON Web Tokens (JWTs) and attaching them to API requests. It includes an example of how to sign a JWT using HMAC-SHA256 and then add the JWT and an API key to the headers of an outgoing request.

## Limitations
evan-hughes marked this conversation as resolved.
Show resolved Hide resolved

- As of now, EW do not support KMI to manage verification keys, hence these keys are fetched from property manager user defined variable which might not be a secure way. More details on user defined variables can be found [here](https://techdocs.akamai.com/property-mgr/docs/user-defined-vars).
evan-hughes marked this conversation as resolved.
Show resolved Hide resolved

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great explanation! Thanks!

## Resources

For more information on JWT Module, please refer to the following resources:

- [JWT API Documentation](https://techdocs.akamai.com/edgeworkers/docs/jwt)
- [Crypto module documentation](https://techdocs.akamai.com/edgeworkers/docs/crypto)
- See the repo [README](https://github.com/akamai/edgeworkers-examples#Resources) for additional guidance.
4 changes: 4 additions & 0 deletions edgecompute/examples/authentication/jwt-signing/bundle.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"edgeworker-version": "0.1",
"description": "Generates a signed JWT for origin verification."
}
80 changes: 80 additions & 0 deletions edgecompute/examples/authentication/jwt-signing/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { logger } from 'log';
evan-hughes marked this conversation as resolved.
Show resolved Hide resolved
import { crypto } from 'crypto';
import { TextEncoder, base64url } from 'encoding';

async function signJWT(payload, secret) {
logger.log('Start: Signing JWT');

try {

// Get current time for issued claim
const currentTime = Math.floor(Date.now() / 1000);

// Set payload 'issued at' (iat) and 'expiration' (exp) claims
payload.iat = currentTime;
payload.exp = currentTime + 300; // Expires in 5 minutes

// JWT header
const header = {
alg: 'HS256'
, typ: 'JWT'
};

// Encode header and payload in base64URL for JWT
const encoder = new TextEncoder();
const encodedHeader = base64url.encode(encoder.encode(JSON.stringify(header)));
const encodedPayload = base64url.encode(encoder.encode(JSON.stringify(payload)));
const message = `${encodedHeader}.${encodedPayload}`;

// Import the secret key for HMAC signing
const keyData = new Uint8Array(encoder.encode(secret));
const cryptoKey = await crypto.subtle.importKey(
'raw'
, keyData.buffer
, { name: 'HMAC', hash: 'SHA-256' }
, false
, ['sign']
);

// Sign the JWT
const signature = await crypto.subtle.sign('HMAC', cryptoKey, encoder.encode(message));
const encodedSignature = base64url.encode(new Uint8Array(signature));

// Return the complete JWT
return `${message}.${encodedSignature}`;

} catch (error) {
logger.error('Error during JWT signing', error);

return error.message;
}
}

export async function onOriginRequest(request) {
logger.log('Start: onOriginRequest');

try {
// Retrieve secrets from environment
const secretKey = request.getVariable('PMUSER_JWT_HMAC_KEY');
const apiKey = request.getVariable('PMUSER_CSS_API_KEY');

// Prepare JWT payload
const payload = {
sub: apiKey
, iss: 'issuer-string-here'
};

// Generate the JWT
const jwt = await signJWT(payload, secretKey);

// Modify outbound request headers
request.removeHeader('Transfer-Encoding');
request.addHeader('X-API-KEY', apiKey);
request.addHeader('X-JWT', `Bearer ${jwt}`);

} catch (error) {
logger.error('Error in onOriginRequest', error);

throw error;
}
}