Skip to content

Generate JWTs on Cloudflare Workers using the WebCrypto API

License

Notifications You must be signed in to change notification settings

rscotten/workers-jwt

 
 

Repository files navigation

workers-jwt

@sagi.io/workers-jwt helps you generate a JWT on Cloudflare Workers with the WebCrypto API. Helper function for GCP Service Accounts included.

CircleCI Coverage Status MIT License version

Installation

$ npm i @sagi.io/workers-jwt

API

We currently expose two methods: getToken for general purpose JWT generation and getTokenFromGCPServiceAccount for JWT generation using a GCP service account.

getToken({ ... })

Function definition:

const getToken = async ({
  privateKeyPEM,
  payload,
  alg = 'RS256',
  cryptoImppl = null,
  headerAdditions = {},
}) => { ... }

Where:

  • privateKeyPEM is the private key string in PEM format.
  • payload is the JSON payload to be signed, i.e. the { aud, iat, exp, iss, sub, scope, ... }.
  • alg is the signing algorithm as defined in RFC7518, currently only RS256 and ES256 are supported.
  • cryptoImpl is a WebCrypto API implementation. Cloudflare Workers support WebCrypto out of the box. For Node.js you can use node-webcrypto-ossl - see examples below and in the tests.
  • headerAdditions is an object with keys and string values to be added to the header of the JWT.

getTokenFromGCPServiceAccount({ ... })

Function definition:

const getTokenFromGCPServiceAccount = async ({
  serviceAccountJSON,
  aud,
  alg = 'RS256',
  cryptoImppl = null,
  expiredAfter = 3600,
  headerAdditions = {},
  payloadAdditions = {}
}) => { ... }

Where:

  • serviceAccountJSON is the service account JSON object .
  • aud is the audience field in the JWT's payload. e.g. https://www.googleapis.com/oauth2/v4/token'.
  • expiredAfter - the duration of the token's validity. Defaults to 1 hour - 3600 seconds.
  • payloadAdditions is an object with keys and string values to be added to the payload of the JWT. Example - { scope: 'https://www.googleapis.com/auth/chat.bot' }.
  • alg, cryptoImpl, headerAdditions are defined as above.

Example

Suppose you'd like to use Firestore's REST API. The first step is to generate a service account with the "Cloud Datastore User" role. Please download the service account and store its contents in the SERVICE_ACCOUNT_JSON_STR environment variable.

The aud is defined by GCP's service definitions and is simply the following concatenated string: 'https://' + SERVICE_NAME + '/' + API__NAME. More info here.

For Firestore the aud is https://firestore.googleapis.com/google.firestore.v1.Firestore.

Cloudflare Workers Usage

Cloudflare Workers expose the crypto global for the Web Crypto API.

const { getTokenFromGCPServiceAccount } = require('@sagi.io/workers-jwt')

const serviceAccountJSON = await ENVIRONMENT.get('SERVICE_ACCOUNT_JSON','json')
const aud = `https://firestore.googleapis.com/google.firestore.v1.Firestore`

const token = await getTokenFromGCPServiceAccount({ serviceAccountJSON, aud} )

const headers = { Authorization: `Bearer ${token}` }

const projectId = 'example-project'
const collection = 'exampleCol'
const document = 'exampleDoc'

const docUrl =
  `https://firestore.googleapis.com/v1/projects/${projectId}/databases/(default)/documents`
  + `/${collection}/${document}`

const response = await fetch(docUrl, { headers })

const documentObj =  await response.json()

Node Usage (version <=14)

We use the node-webcrypto-ossl package to imitate the Web Crypto API in Node.

const { Crytpo }= require('node-webcrypto-ossl');
const cryptoImpl  = new Crypto();
const { getTokenFromGCPServiceAccount } = require('@sagi.io/workers-jwt')

const serviceAccountJSON = { ... }
const aud = `https://firestore.googleapis.com/google.firestore.v1.Firestore`

const token = await getTokenFromGCPServiceAccount({ serviceAccountJSON, aud, cryptoImpl } )

<... SAME AS CLOUDFLARE WORKERS ...>

Node Usage (version 15+)

Node 15 introduces the Web Crypto API, so you don't have to pass in cryptoImpl.

const { getTokenFromGCPServiceAccount } = require('@sagi.io/workers-jwt')

const serviceAccountJSON = { ... }
const aud = 'https://firestore.googleapis.com/google.firestore.v1.Firestore';

const token = await getTokenFromGCPServiceAccount({ serviceAccountJSON, aud });

<... SAME AS CLOUDFLARE WORKERS ...>

About

Generate JWTs on Cloudflare Workers using the WebCrypto API

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 100.0%